SQL Convert Seconds into Day:Hour:Min:Sec - datetime

Topic says it all. I'm trying to do some magic, via a function, that turns a second integer into a string "DD:HH:MM:SS".
Snip
input: 278543
output: "3D 5H 22M 23S "
What I'd like to do, more gracefully if possible, is pad the numbers (So that 5M shows as 05M) and right align them so that "3D 5H 22M 23S " is " 3D 5H 22M 23S" instead.
edit: Latest cut that seems to work. Would love to have it prettier, but this definitely works as far as I can tell:
CREATE FUNCTION DHMS(secondsElapsed INT)
RETURNS Char(20)
LANGUAGE SQL
NO EXTERNAL ACTION
DETERMINISTIC
BEGIN
DECLARE Dy Integer;
DECLARE Hr Integer;
DECLARE Mn Integer;
DECLARE Sc Integer;
SET Dy = Cast( secondsElapsed / 86400 as Int);
SET Hr = Cast(MOD( secondsElapsed, 86400 ) / 3600 as Int);
SET Mn = Cast(MOD( secondsElapsed, 3600 ) / 60 as Int);
SET Sc = Cast(MOD( secondsElapsed, 60 ) as Int);
RETURN REPEAT(' ',6-LENGTH(RTRIM(CAST(Dy AS CHAR(6))))) || Dy || 'D '
|| REPEAT('0',2-LENGTH(RTRIM(CAST(Hr AS CHAR(6))))) || Hr || 'H '
|| REPEAT('0',2-LENGTH(RTRIM(CAST(Mn AS CHAR(6))))) || Mn || 'M '
|| REPEAT('0',2-LENGTH(RTRIM(CAST(Sc AS CHAR(6))))) || Sc || 'S';
END

You were on the right track using LPAD(), since it can pad with zero or any other string. CHAR(15) is not enough to format the output the way you want and still allow five positions for the number of days, which is the length you specified in your code.
CREATE OR REPLACE FUNCTION DHMS(secondsElapsed INT)
RETURNS Char(18)
LANGUAGE SQL
NO EXTERNAL ACTION
DETERMINISTIC
RETURN LPAD( secondsElapsed / 86400 , 5 ) || 'D '
|| LPAD( MOD( secondsElapsed, 86400 ) / 3600, 2, '0') || 'H '
|| LPAD( MOD( secondsElapsed, 3600 ) / 60, 2, '0' ) || 'M '
|| LPAD( MOD( secondsElapsed, 60 ), 2, '0' ) || 'S'
;

declare #seconds int
set #seconds = 900000000
select cast(#seconds/86400 as varchar(50))+':'+Convert(VarChar, DateAdd(S, #seconds, 0), 108)

Related

SQL Loop Executing after intended

I am attempting to run this code, I know the elements of the Loop are working, and I know the update statement does update. When I run the script with some print statements, it prints the UPDATE information first, then the LOOP information, therefore the update has no information.
PROCEDURE UpdateGridStats(p_grid_name VARCHAR2, p_region_name VARCHAR2) IS
CURSOR c1 IS
SELECT grd.globalid grid_globalid, wp.globalid workpoint_globalid, wp.feature_class_name workpoint_fcname,
tt.work_order_task_type task_type_name
FROM workorderpoint_evw wp, rpt_grid grd, workordertasktype_evw tt
WHERE grd.grid_name = p_grid_name
AND wp.work_order_task_type_globalid = tt.globalid
AND grd.rpt_region = p_region_name
AND sde.st_relation_operators.st_within_f(wp.shape, grd.shape) = 1;
v_count NUMBER := 0;
v_pole_insp_count NUMBER := 0;
v_pole_damage_count NUMBER := 0;
v_cond_damage_count NUMBER := 0;
BEGIN
FOR work_rec IN c1
LOOP
BEGIN
v_count := v_count + 1;
IF work_rec.task_type_name = 'Pole Inspection'
THEN
v_pole_insp_count := v_pole_insp_count + 1;
END IF;
IF work_rec.task_type_name = 'Pole Damage'
THEN
v_pole_damage_count := v_pole_damage_count + 1;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('==> No data found for work record ');
END;
END LOOP;
dbms_output.put_line(v_pole_damage_count || ',' ||v_pole_insp_count);
UPDATE rpt_grid grd SET da_pole_count = v_pole_damage_count, ins_structure_count = v_pole_insp_count
WHERE grd.grid_name = p_grid_name
AND grd.rpt_region = p_region_name;
END UpdateGridStats;
Maybe you just forgot to commit your changes?
Here is a simpler version of your stored procedure.
CREATE OR REPLACE PROCEDURE update_grid_stats(p_grid_name VARCHAR2, p_region_name VARCHAR2)
IS
v_ins_structure_count rpt_grid.ins_structure_count%TYPE;
v_da_pole_count rpt_grid.da_pole_count%TYPE;
BEGIN
UPDATE rpt_grid grd
SET (ins_structure_count, da_pole_count) =
(
SELECT
COUNT(CASE WHEN tt.work_order_task_type = 'Pole Inspection' THEN 1 END),
COUNT(CASE WHEN tt.work_order_task_type = 'Pole Damage' THEN 1 END)
FROM workorderpoint_evw wp
JOIN workordertasktype_evw tt ON wp.work_order_task_type_globalid = tt.globalid
WHERE sde.st_relation_operators.st_within_f(wp.shape, grd.shape) = 1
)
WHERE grd.grid_name = p_grid_name
AND grd.rpt_region = p_region_name
RETURNING ins_structure_count, da_pole_count
INTO v_ins_structure_count, v_da_pole_count;
dbms_output.put_line(
SQL%ROWCOUNT || ' rows got updated. Values: ' ||
'ins_structure_count = ' || v_ins_structure_count ||
', da_pole_count = ' || v_da_pole_count
);
COMMIT;
END update_grid_stats;
The variables and the RETURNING clause are merely needed for the output. If you don't need the output, you can remove them.
if I understand correcatally, the proc works OK, but the print statemnts are not. I beleve the print operations are on a different thread. To overcome this issue, try to replace your pront statment with raiserror function :
declare #mag varchar(max) = 'Hllo world'
raiserror ( #ERR_MSG ,0, 1) with nowait;

PL-SQL - ORA-00932: inconsistent datatypes: expected DATE got NUMBER

Trying to loop through a sysrefcursor but getting ORA-00932 seems like when looping, the dates, e.g.: 1990/01/01 get operated on as if they were a division ?
set serveroutput on;
DECLARE
email VARCHAR2(1000);
webcastEngagement NUMBER(10,1);
videoEngagement NUMBER(10,1);
documentEngagement NUMBER(10,1);
totalEngagement NUMBER(10,1);
--averageEngagement NUMBER(4,1);
totalWebcastSeconds NUMBER(10);
engagementMinutes NUMBER(10, 1);
last30DaysEM NUMBER(10, 1);
last60DaysEM NUMBER(10, 1);
fromDate DATE;
engagementPrediction NUMBER(10);
engagementLevel VARCHAR2(6 CHAR);
totalWebcasts NUMBER(10);
totalVideos NUMBER(10);
totalDocuments NUMBER(10);
totalURLs NUMBER(10);
firstName VARCHAR2(1000);
lastName VARCHAR2(1000);
company VARCHAR2(1000);
jobTitle VARCHAR2(1000);
workPhone VARCHAR2(1000);
clientName VARCHAR2(1000);
portalEnabled VARCHAR2(5);
resources NUMBER(10);
videoProfile NUMBER;
showInterestCloud VARCHAR2(10);
attended VARCHAR(1);
leadIndex NUMBER := 1;
clientFunnelStages VARCHAR2(4000);
funnelStage VARCHAR2(100 CHAR);
partnerref VARCHAR2(4000);
experienceProfileId NUMBER := 525;
resp ON24MASTER.WEBCAST_REPORTS.ResultSetCursor;
BEGIN
resp := WEBCAST_REPORTS.LEAD_BASIC_INFO('testqa_11071113#inbfw.com',22917);
LOOP
FETCH resp into email, webcastEngagement,videoEngagement,documentEngagement, totalEngagement,totalWebcastSeconds,engagementMinutes,last30DaysEM,last60DaysEM,
fromDate,-- also tried to_date(fromDate, 'YYYY-MM-DD')
engagementPrediction,engagementLevel,totalWebcasts, totalVideos, totalDocuments, totalURLs, firstName,lastName,company, jobTitle,workPhone,
clientName,portalEnabled,resources,videoProfile,showInterestCloud,attended,leadIndex,clientFunnelStages,funnelStage,partnerref,experienceProfileId;
dbms_output.put_line(email|| ' ---- ' || webcastEngagement|| ' ---- ' ||videoEngagement|| ' ---- ' ||documentEngagement|| ' ---- ' || totalEngagement|| ' ---- ' ||totalWebcastSeconds|| ' ---- ' ||engagementMinutes|| ' ---- ' ||last30DaysEM|| ' ---- ' ||last60DaysEM|| ' ---- ' ||fromDate|| ' ---- ' ||
engagementPrediction|| ' ---- ' ||engagementLevel|| ' ---- ' ||totalWebcasts|| ' ---- ' || totalVideos|| ' ---- ' || totalDocuments|| ' ---- ' || totalURLs|| ' ---- ' || firstName|| ' ---- ' ||lastName|| ' ---- ' ||company|| ' ---- ' || jobTitle|| ' ---- ' ||workPhone|| ' ---- ' ||
clientName|| ' ---- ' ||portalEnabled|| ' ---- ' ||resources|| ' ---- ' ||videoProfile|| ' ---- ' ||showInterestCloud|| ' ---- ' ||attended|| ' ---- ' ||leadIndex|| ' ---- ' ||clientFunnelStages|| ' ---- ' ||funnelStage|| ' ---- ' ||partnerref|| ' ---- ' ||experienceProfileId);
exit when resp%notfound;
END LOOP;
CLOSE resp;
END;
/
in function body, fromDate DATE does very simple things, it will be assigned similar to: fromDate := SYSDATE - 60
My goal is to output the result set.
What currently works, has horrible output:
variable rc refcursor;
DECLARE
LEADEMAIL VARCHAR2(200);
CLIENTID NUMBER;
BEGIN
LEADEMAIL := 'nunyo#business.com';
CLIENTID := 22921;
:rc := WEBCAST_REPORTS.LEAD_BASIC_INFO(
LEADEMAIL => LEADEMAIL,
CLIENTID => CLIENTID
);
END;
/
print rc;
This is part of the output:
EMAIL CLIENT_ID
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------
CLIENT_NAME CG_ACTIVE WEBCAST_ENGAGEMENT VIDEO_ENGAGEMENT DOCUMENT_ENGAGEMENT TOTAL_ENGAGEMENT AVG_WEBCAST_MINUTES NGAGEMENT_MINUTES TOTAL_WEBCASTS
TOTAL_VIDEOS TOTAL_DOCUMENTS TOTAL_URLS A PREDIC LAST_30D_ENGAGEMENT_MINUTES LAST_60D_ENGAGEMENT_MINUTES ENGAGEMENT_LEVEL FIRST_NAME
------------ --------------- ---------- - ------ --------------------------- --------------------------- -------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
LAST_NAME
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
JOB_TITLE
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
WORK_PHONE
COMPANY REGISTRATION_SOURCE H H H H RESOURCES S
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------- - - - - ---------- -
FUNNEL_STAGE
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 0 0 Y HIGH 34 34 LOW test
EMAIL CLIENT_ID
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------
CLIENT_NAME
Update
FUNCTION LEAD_BASIC_INFO(
leadEmail VARCHAR2,
clientId NUMBER
) RETURN ResultSetCursor IS
-- rest of the variables
-- more code
OPEN resultSet FOR
select
nvl(email, leadEmail) EMAIL,
clientId CLIENT_ID,
clientName CLIENT_NAME,
portalEnabled CG_ACTIVE,
nvl(webcastEngagement, 0) WEBCAST_ENGAGEMENT,
nvl(videoEngagement, 0) VIDEO_ENGAGEMENT,
nvl(documentEngagement, 0) DOCUMENT_ENGAGEMENT,
nvl(totalEngagement, 0) TOTAL_ENGAGEMENT,
--nvl(averageEngagement, 0) AVERAGE_ENGAGEMENT,
case when nvl(totalWebcasts, 0) = 0
then 0
else nvl(round((totalWebcastSeconds/totalWebcasts)/60, 1), 0)
end AVG_WEBCAST_MINUTES,
nvl(engagementMinutes, 0) ENGAGEMENT_MINUTES,
nvl(totalWebcasts, 0) TOTAL_WEBCASTS,
nvl(totalVideos, 0) TOTAL_VIDEOS,
nvl(totalDocuments, 0) TOTAL_DOCUMENTS,
nvl(totalURLs, 0) TOTAL_URLS,
case when (nvl(totalWebcasts, 0) + nvl(totalVideos, 0) + nvl(totalDocuments, 0) + nvl(totalURLs, 0) > 0) then 'Y' else 'N' end ATTENDED,
case engagementPrediction when 1 then 'LOW' when 2 then 'MEDIUM' when 3 then 'HIGH' else '' end as PREDICTIVE_ENGAGEMENT,
last30DaysEM as LAST_30D_ENGAGEMENT_MINUTES,
last60DaysEM as LAST_60D_ENGAGEMENT_MINUTES,
engagementLevel as ENGAGEMENT_LEVEL,
nvl(firstName, '') FIRST_NAME,
nvl(lastName, '') LAST_NAME,
nvl(jobTitle, '') JOB_TITLE,
nvl(workPhone, '') WORK_PHONE,
nvl(company, '') COMPANY,
nvl(partnerref, '') REGISTRATION_SOURCE,
case when (length(trim(firstName)) > 0 or length(trim(lastName)) > 0)
then 'Y'
else 'N'
end HAS_NAME,
case when (length(trim(jobTitle)) > 0)
then 'Y'
else 'N'
end HAS_JOB_TITLE,
case when (length(trim(workPhone)) > 0)
then 'Y'
else 'N'
end HAS_WORK_PHONE,
case when (length(trim(company)) > 0)
then 'Y'
else 'N'
end HAS_COMPANY,
nvl(resources, 0) RESOURCES,
case when (lower(showInterestCloud) = 'yes')
then 'Y'
else 'N'
end SHOW_BIS,
funnelStage FUNNEL_STAGE
from dual;
RETURN resultSet;
END LEAD_BASIC_INFO;
Your `fetch into is expecting a date in the 10th column:
FETCH resp into email, -- 1
webcastEngagement, -- 2
videoEngagement, -- 3
documentEngagement, -- 4
totalEngagement, -- 5
totalWebcastSeconds, -- 6
engagementMinutes, -- 7
last30DaysEM, -- 8
last60DaysEM, -- 9
fromDate, -- 10
...
The 10th column in your function's query is a number:
OPEN resultSet FOR
select
nvl(email, leadEmail) EMAIL, -- 1
clientId CLIENT_ID, -- 2
clientName CLIENT_NAME, -- 3
portalEnabled CG_ACTIVE, -- 4
nvl(webcastEngagement, 0) WEBCAST_ENGAGEMENT, -- 5
nvl(videoEngagement, 0) VIDEO_ENGAGEMENT, -- 6
nvl(documentEngagement, 0) DOCUMENT_ENGAGEMENT, -- 7
nvl(totalEngagement, 0) TOTAL_ENGAGEMENT, -- 8
--nvl(averageEngagement, 0) AVERAGE_ENGAGEMENT,
case when nvl(totalWebcasts, 0) = 0
then 0
else nvl(round((totalWebcastSeconds/totalWebcasts)/60, 1), 0)
end AVG_WEBCAST_MINUTES, -- 9
nvl(engagementMinutes, 0) ENGAGEMENT_MINUTES, -- 10
...
The two lists of columns/variables seem to be in completely different orders. For instance, WEBCAST_ENGAGEMENT is the fifth column in your query, but second in your fetch.
Fetch is positional - it doesn't matter what the result set columns are called (or if they are aliased at all), you have to fetch them into the variables in the same order they appear in the query's select list.
You don't actually seem to have any date columns in your query, called fromDate or anything else.
So, you are trying to fetch the number supplied in the query's 10th column, the nvl() that's aliased as ENGAGEMENT_MINUTES, into the date variable fromDate. Hence the error - expected DATE (because that's how fromDate is declared) got NUMBER (because that's what ENGAGEMENT_MINUTES is).

Comparing Multiple Values from one table to Multiple Values in another

I have a PL/SQL stored function script I am writing and I have run into a problem.
I need to find ALL Applicants who possess ALL the skills needed for a task and display them.
I have a method where I have individually read in Applicant's skills into a VARCHAR2 string and all the Skills required into another. If I could separate these strings into individual words I could compare the two with LIKE '% <data> %'.
How would I go about this (or what is an alternative method)?
CREATE OR REPLACE FUNCTION FUBARR(num IN NUMBER) RETURN VARCHAR IS
string_position VARCHAR2(128);
string_applicant VARCHAR2(128);
string_results VARCHAR2(128);
BEGIN
string_position := '';
string_applicant := '';
FOR SKILLS_row IN (SELECT sname FROM SNEEDED WHERE pnumber = num)
LOOP
string_position := string_position || SKILLS_row.sname || ' ';
END LOOP;
FOR EVERYBODY_row IN (SELECT UNIQUE anumber FROM SPOSSESSED ORDER BY anumber)
LOOP
FOR APPLICANTS_row IN (SELECT sname FROM SPOSSESSED WHERE SPOSSESSED.anumber = EVERYBODY_row.anumber)
LOOP
string_applicant := string_applicant || APPLICANTS_row.sname || ' ';
END LOOP;
--DBMS_OUTPUT.PUT_LINE(EVERYBODY_row.anumber || ' ' || string_applicant);
--IF blaah != LIKE BLAh
IF
string_applicant := '';
END LOOP;
--DBMS_OUTPUT.PUT_LINE(string_position);
--RETURN (string_position);
RETURN('help');
END FUBARR;
/
why not simply select all spossesed - records, where the number of associated skills of the desired num is equal to the plain number of sneeded - skills of that num:
SELECT *
FROM SPOSSESSED sp
WHERE (SELECT COUNT(*) FROM SNEEDED s
WHERE s.pnumber = num) =
(SELECT COUNT(*) FROM SNEEDED s
JOIN SPOSSESSED p ON p.sname = s.sname
WHERE s.pnumber = num and p.anumber = sp.anumber)
or using the ANY construct:
SELECT sp.anumber, COUNT(*)
FROM SPOSSESSED sp
WHERE sp.sname = ANY (SELECT s.sname FROM SNEEDED s WHERE s.pnumber = num)
GROUP BY sp.anumber

Calculate total hours between 2 time stamps?

How we can make a store procedure in between time?
like,
Total Hr=(( outtime - intime) - (breakin time - breakout time) )
create procedure sp_time_outtime
#id bigint
as
begin
declare
#totalhour as nvarchar(50),
#tth as bigint,
#ttm as bigint,
#inhour as bigint,
#outhour as bigint,
#breakinhour as bigint select #tth = datediff(mi, intime, (case when breakouttime is null then isnull(breakintime,GETDATE()) else GETDATE() end) ) from time where empid=#id and CONVERT(date,GETDATE()) = CONVERT(date,[date])
select #ttm = datediff(mi, isnull(breakintime,'1/1/1990'),ISNULL(breakouttime,isnull (breakintime,'1/1/1990'))) from time where empid=#id and CONVERT(date,GETDATE()) = CONVERT(date,[date])
select #totalhour = (#tth -#ttm)
SET #totalhour = CASE WHEN (#tth -#ttm) >= 60 THEN (SELECT CAST(((#tth -#ttm) / 60) AS VARCHAR(2)) + ' :H :' +
CASE WHEN ((#tth -#ttm) % 60) > 0 THEN
CAST(((#tth -#ttm) % 60) AS VARCHAR(2)) + ' M'
ELSE
''
END) ELSE
CAST(((#tth -#ttm) % 60) AS VARCHAR(2)) + 'M'
END
if ((select outtime from time where empid=#id and convert(date,GETDATE())=CONVERT(date,[date])) IS NULL)
begin
update time set outtime=GETDATE(),totalhour=#totalhour where
empid=#id and CONVERT(date,GETDATE()) = CONVERT(date,[date])
end END

Get Installation Sequence of Oracle Objects

Ok, I have a complex recursion problem. I want to get a dependecy installation sequence of all of my objcts (all_objects table) in my Oracle 11g database.
First I have created a view holding all dependencies
create or replace
view REALLY_ALL_DEPENDENCIES as
select *
from ALL_DEPENDENCIES
union
select owner, index_name, 'INDEX', table_owner, table_name, table_type, null, null
from all_indexes
union
select p.owner, p.table_name, 'TABLE', f.owner, f.table_name, 'TABLE', null, null
from all_constraints p
join all_constraints f
on F.R_CONSTRAINT_NAME = P.CONSTRAINT_NAME
and F.CONSTRAINT_TYPE = 'R'
and p.constraint_type='P'
;
/
EDIT
I have tried do concate all dependencies by using this function:
create
or replace
function dependency(
i_name varchar2
,i_type varchar2
,i_owner varchar2
,i_level number := 0
,i_token clob := ' ') return clob
is
l_token clob := i_token;
l_exist number := 0;
begin
select count(*) into l_exist
from all_objects
where object_name = i_name
and object_type = i_type
and owner = i_owner;
if l_exist > 0 then
l_token := l_token || ';' || i_level || ';' ||
i_name || ':' || i_type || ':' || i_owner;
else
-- if not exist function recursion is finished
return l_token;
end if;
for tupl in (
select distinct
referenced_name
,referenced_type
,referenced_owner
from REALLY_ALL_DEPENDENCIES
where name = i_name
and type = i_type
and owner = i_owner
)
loop
-- if cyclic dependency stop and shout!
if i_token like '%' || tupl.referenced_name || ':' || tupl.referenced_type || ':' || tupl.referenced_owner || '%' then
select count(*) into l_exist
from REALLY_ALL_DEPENDENCIES
where name = tupl.referenced_name
and type = tupl.referenced_type
and owner = tupl.referenced_owner;
if l_exist > 0 then
return '!!!CYCLIC!!! (' || i_level || ';' || tupl.referenced_name || ':' || tupl.referenced_type || ':' || tupl.referenced_owner || '):' || l_token;
end if;
end if;
-- go into recursion
l_token := dependency(
tupl.referenced_name
,tupl.referenced_type
,i_owner /* I just want my own sources */
,i_level +1
,l_token);
end loop;
-- no cyclic condition and loop is finished
return l_token;
end;
/
And I can query through
select
object_name
,object_type
,owner
,to_char(dependency(object_name, object_type, owner)) as dependecy
from all_objects
where owner = 'SYSTEM'
;
Ok, maybe it is something like "cheating" but you can not do cyclic dependencies at creation time. So at least as a human beeing I am only able to create one object after another :-) And this sequence should be "reverse engineer able".
Now I am more interested in a solution than before ;-) And it is still about the tricky part ... "How can I select all soures from a schema orderd by its installation sequence (dependent objects list prior the using object)"?
It is just some kind of sorting problem, insn't it?
Usually you "cheat" by creating the objects in a particular order. For example, you might make sequences first (they have zero dependencies). Then you might do tables. After that, package specs, then package bodies, and so on.
Keep in mind that it is possible to have cyclic dependencies between packages, so there are cases where it will be impossible to satisfy all dependencies at creation anyway.
What's the business case here? Is there a real "problem" or just an exercise?
EDIT
The export tool we use exports objects in the following order:
Database Links
Sequences
Types
Tables
Views
Primary Keys
Indexes
Foreign Keys
Constraints
Triggers
Materialized Views
Materialized View Logs
Package Specs
Package Bodies
Procedures
Functions
At the end, we run the dbms_utility.compile_schema procedure to make sure everything is valid and no dependencies are missed. If you use other object types than these, I'm not sure where they'd go in this sequence.
Ok, I had some time to look at the job again and I want to share the results. Maybe anotherone comes across this thread searching for a solution. First of all I did the SQLs as SYS but I think you can do it in every schema using public synonyms.
The Procedure "exec obj_install_seq.make_install('SCOTT');" makes a clob containing a sql+ compatible sql file, assuming your sources are called "object_name.object_type.sql". Just spool it out.
Cheers
Chris
create global temporary table DEPENDENCIES on commit delete rows as
select * from ALL_DEPENDENCIES where 1=2 ;
/
create global temporary table install_seq(
idx number
,seq number
,iter number
,owner varchar2(30)
,name varchar2(30)
,type varchar2(30)
) on commit delete rows;
/
create global temporary table loop_chk(
iter number
,lvl number
,owner varchar2(30)
,name varchar2(30)
,type varchar2(30)
) on commit delete rows;
/
create or replace package obj_install_seq is
procedure make_install(i_schema varchar2 := 'SYSTEM');
end;
/
create or replace package body obj_install_seq is
subtype install_seq_t is install_seq%rowtype;
type dependency_list_t is table of DEPENDENCIES%rowtype;
procedure set_list_data(i_schema varchar2 := user)
is
l_owner varchar2(30) := i_schema;
begin
-- collect all dependencies
insert into DEPENDENCIES
select *
from (select *
from ALL_DEPENDENCIES
where owner = l_owner
and referenced_owner = l_owner
union
select owner, index_name, 'INDEX', table_owner, table_name, table_type, null, null
from all_indexes
where owner = l_owner
and table_owner = l_owner
union
select p.owner, p.table_name, 'TABLE', f.owner, f.table_name, 'TABLE', null, null
from all_constraints p
join all_constraints f
on F.R_CONSTRAINT_NAME = P.CONSTRAINT_NAME
and F.CONSTRAINT_TYPE = 'R'
and p.constraint_type='P'
and p.owner = f.owner
where p.owner = l_owner
) all_dep_tab;
-- collect all objects
insert into install_seq
select rownum, null,null, owner, object_name, object_type
from (select distinct owner, object_name, object_type, created
from all_objects
where owner = l_owner
order by created) objs;
end;
function is_referencing(
i_owner varchar2
,i_name varchar2
,i_type varchar2
,i_iter number
,i_level number := 0
) return boolean
is
l_cnt number;
begin
select count(*) into l_cnt
from loop_chk
where name = i_name
and owner = i_owner
and type = i_type
and iter = i_iter
and lvl < i_level;
insert into loop_chk values(i_iter,i_level,i_owner,i_name,i_type);
if l_cnt > 0 then
return true;
else
return false;
end if;
end;
procedure set_seq(
i_owner varchar2
,i_name varchar2
,i_type varchar2
,i_iter number
,i_level number := 0)
is
-- l_dep all_dependencies%rowtype;
l_idx number;
l_level number := i_level +1;
l_dep_list dependency_list_t;
l_cnt number;
begin
-- check for dependend source
begin
select * bulk collect into l_dep_list
from dependencies
where name = i_name
and owner = i_owner
and type = i_type;
if l_dep_list.count <= 0 then
-- recursion finished
return;
end if;
end;
for i in 1..l_dep_list.count loop
if is_referencing(
l_dep_list(i).referenced_owner
,l_dep_list(i).referenced_name
,l_dep_list(i).referenced_type
,i_iter
,i_level
) then
-- cyclic dependecy
update install_seq
set seq = 999
,iter = i_iter
where name = l_dep_list(i).referenced_name
and owner = l_dep_list(i).referenced_owner
and type = l_dep_list(i).referenced_type;
else
--chek if sequence is earlier
select count(*) into l_cnt
from install_seq
where name = l_dep_list(i).referenced_name
and owner = l_dep_list(i).referenced_owner
and type = l_dep_list(i).referenced_type
and seq > l_level *-1;
-- set sequence
if l_cnt > 0 then
update install_seq
set seq = l_level *-1
,iter = i_iter
where name = l_dep_list(i).referenced_name
and owner = l_dep_list(i).referenced_owner
and type = l_dep_list(i).referenced_type;
end if;
-- go recusrion
set_seq(
l_dep_list(i).referenced_owner
,l_dep_list(i).referenced_name
,l_dep_list(i).referenced_type
,i_iter + (i-1)
,l_level
);
end if;
end loop;
end;
function get_next_idx return number
is
l_idx number;
begin
select min(idx) into l_idx
from install_seq
where seq is null;
return l_idx;
end;
procedure make_install(i_schema varchar2 := 'SYSTEM')
is
l_obj install_seq_t;
l_idx number;
l_iter number := 0;
l_install_clob clob := chr(10);
begin
set_list_data(i_schema);
l_idx := get_next_idx;
while l_idx is not null loop
l_iter := l_iter +1;
select * into l_obj from install_seq where idx = l_idx;
update install_seq set iter = l_iter where idx = l_idx;
update install_seq set seq = 0 where idx = l_idx;
set_seq(l_obj.owner,l_obj.name,l_obj.type,l_iter);
l_idx := get_next_idx;
end loop;
for tupl in ( select * from install_seq order by seq, iter, idx ) loop
l_install_clob := l_install_clob || '#' ||
replace(tupl.name,' ' ,'') || '.' ||
replace(tupl.type,' ' ,'') || '.sql' ||
chr(10);
end loop;
l_install_clob := l_install_clob ||
'exec dbms_utility.compile_schema(''' || upper(i_schema) || ''');';
-- do with the install file what you want
DBMS_OUTPUT.PUT_LINE(dbms_lob.substr(l_install_clob,4000));
end;
end;
/

Resources