A reader, June 10, 2003 - 10:13 am UTC
hierarchial query
A reader, June 10, 2003 - 11:10 am UTC
Excellent
8.1.7 sys_connect_by_path
A reader, June 10, 2003 - 12:53 pm UTC
sys_connect_by_path is available in 8.1.7 as an undocumented feature, which can be enabled by
alter session set "_new_connect_by_enabled" = true;
or setting this parameter in init.ora
June 10, 2003 - 12:56 pm UTC
i would strongly discourage that.
not to "get you to upgrade", but because as with ALL _ parameters, there can be serious and unintentional side effects..
"just say no"
Excellent
A reader, June 10, 2003 - 1:01 pm UTC
Hierarchical Query
A reader, June 14, 2004 - 7:02 pm UTC
Hi Tom
Consider the table structures as below
Table A
ID PARENT_ID TYPE STATUS
1 1 S PROAPP
2 1 R PROAPP
3 2 R PROAPP
4 3 C APP
5 5 S PROAPP
6 5 R PROAPP
7 6 C APP
Table B
ID VALUE
1 Value one
5 Value two
Now, I have to write a query that will select records from Table A with STATUS = 'APP'( in the above example ids 4 and 7 ) but trawl through to get ids 1 and 5 ( TYPE = 'S' and parents of ids 4 and 7 ) and then join with Table B to retrieve VALUE column. The volume is high in both the tables ( Table A : 200000 records, Table B: 5000000 records ).
I had raised a similar sort of query before and received an excellent feedback.
Thanks in advance
June 15, 2004 - 2:59 pm UTC
parents of 4 and 7 seem to be 3 and 6??
sorry, did not follow this one at all.
Hierarchical Query
A reader, June 16, 2004 - 5:26 am UTC
Sorry Tom - Ids 1 and 5 are ultimate parents of ids 4 and 7 in the above example. Ultimate parents always have a type value of S. Only ultimate parent Ids have values in Table B.
Many Thanks
June 16, 2004 - 12:41 pm UTC
hate to be a stickler, but -- create table.... insert into table......
Hierarchical Query
A reader, June 17, 2004 - 6:04 am UTC
No problem - Please find enclosed the scripts
SQL> create table a
2 (id number,
3 parent_id number,
4 type varchar2(1),
5 status varchar2(10));
Table created.
SQL> insert into a values(1,1,'S','PROAPP');
1 row created.
SQL> insert into a values(2,1,'R','PROAPP');
1 row created.
SQL> insert into a values(3,2,'R','PROAPP');
1 row created.
SQL> insert into a values(4,3,'C','APP');
1 row created.
SQL> insert into a values(5,5,'S','PROAPP');
1 row created.
SQL> insert into a values(6,5,'R','PROAPP');
1 row created.
SQL> insert into a values(7,6,'C','APP');
1 row created.
SQL> commit;
Commit complete.
SQL> create table b
2 (id number,
3 value varchar2(2000));
Table created.
SQL> insert into b values(1,'Value One');
1 row created.
SQL> insert into b values(5,'Value Two');
1 row created.
SQL> commit;
Commit complete.
Thanks
June 17, 2004 - 10:13 am UTC
ops$tkyte@ORA9IR2> select a.*, b.*
2 from (
3 select a.* ,
4 to_number( substr(
5 (select max(to_char(level,'fm00000')||id)
6 from a a2
7 start with id = a.parent_id
8 connect by prior parent_id = id and prior parent_id <> prior id), 6 ) ) ultimate_pid
9 from a
10 where status = 'APP'
11 ) a, b
12 where b.id = a.ultimate_pid
13 /
ID PARENT_ID T STATUS ULTIMATE_PID ID VALUE
---------- ---------- - ---------- ------------ ---------- ---------------
4 3 C APP 1 1 Value One
7 6 C APP 5 5 Value Two
Hierarchical Query
A reader, June 17, 2004 - 11:34 am UTC
Thanks Tom - This is exactly what I wanted.
is this possible with just SQL at all
j., September 23, 2004 - 6:23 pm UTC
hi tom,
i've to select all "chains" (sets of related entries under a certain node) that don't include a given node.
create table tab(
id number,
parentid number,
constraint pk primary key( id ),
constraint fk foreign key( parentid ) references tab( id )
)
/
insert into tab( id, parentid ) values( 1, null ) ;
insert into tab( id, parentid ) values( 2, 1 ) ;
insert into tab( id, parentid ) values( 3, 2 ) ;
insert into tab( id, parentid ) values( 4, null ) ;
insert into tab( id, parentid ) values( 5, 4 ) ;
commit ;
select level, id, parentid
from tab
start with parentid is null
connect by prior id = parentid
order by id ;
is there a way to skip - lets say - the "chain" 1->2->3 (all nodes under id = 1) due to the fact that this subset includes the node with id = 3?
September 24, 2004 - 10:09 am UTC
ops$tkyte@ORA9IR2> variable the_bad_guy number;
ops$tkyte@ORA9IR2> exec :the_bad_guy := 3
PL/SQL procedure successfully completed.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select substr( rpad('*', 2*level, '*' ) || id, 1, 20 ) idstr
2 from tab
3 start with
4 ( parentid is null
5 and
6 not exists ( select null
7 from tab t2
8 where id = :the_bad_guy
9 start with parentid = tab.id
10 connect by prior id = parentid )
11 )
12 connect by prior id = parentid
13 /
IDSTR
--------------------
**4
****5
Should '1' be a good guy?
Gabe, September 24, 2004 - 10:31 am UTC
flip@flop> variable the_bad_guy number;
flip@flop> exec :the_bad_guy := 1
PL/SQL procedure successfully completed.
flip@flop> select substr( rpad('*', 2*level, '*' ) || id, 1, 20 ) idstr
2 from tab
3 start with parentid is null
4 connect by prior id = parentid
5 order by id ;
IDSTR
------------------------------------------------------
**1
****2
******3
**4
****5
flip@flop> select substr( rpad('*', 2*level, '*' ) || id, 1, 20 ) idstr
2 from tab
3 start with
4 ( parentid is null
5 and
6 not exists ( select null
7 from tab t2
8 where id = :the_bad_guy
9 start with parentid = tab.id
10 connect by prior id = parentid )
11 )
12 connect by prior id = parentid
13 /
IDSTR
----------------------------------------------------
**1
****2
******3
**4
****5
Oh ... and "chains" is a bit confusing in that question ... "subtree" would be a bit more appropriate.
Thanks.
September 24, 2004 - 11:40 am UTC
he wanted to nuke any "tree" with "3" in it.
...
is there a way to skip - lets say - the "chain" 1->2->3 (all nodes under id = 1)
due to the fact that this subset includes the node with id = 3?
.....
we weren't given "1", we had "3" to work with.
compressing number of rows using Hierarchical query
Anand Kothapeta, November 09, 2005 - 11:11 am UTC
Hi Tom,
since we talked about connect by I have question. I have the following table
key1 sdt edt val1
--- ---------- -------- -----
1 1/1/2000 2/1/2000 1
1 2/1/2000 3/1/2000 1
1 3/1/2000 4/1/2000 2
1 4/1/2000 5/1/2000 2
1 5/1/2000 6/1/2000 2
1 6/1/2000 7/1/2000 3
1 7/1/2000 8/1/2000 1
basically for a given key between given dates it had a value, kinda historical table. The problem is that as you can see first two rows can be compressed into one. First two rows should become one (1, 1/1/2000, 3/1/2003, 1) as it had same values between first two rows. Same with the next three row (1,3/1/2000,6/1/2000,2). I did this to get to the following result.
SELECT key1, MIN(sdt), MAX(edt), val1
FROM (SELECT LEVEL, SYS_CONNECT_BY_PATH( TO_CHAR(sdt,'yyyymmdd') , '/') path, key1, sdt, edt, val1
FROM myt t1
START WITH sdt = (SELECT MIN(sdt) FROM myt t2 WHERE t2.key1 = t1.key1 AND t2.val1 = t1.val1)
CONNECT BY sdt = PRIOR edt
AND key1 = PRIOR key1
AND val1 = PRIOR val1
)
GROUP BY key1, SUBSTR(path,1,8), val1;
I was wondering if there is a better way to do this. what kinda indexes would help this query.
key1 sdt edt val1
--- ---------- -------- -----
1 1/1/2000 3/1/2000 1
1 3/1/2000 6/1/2000 2
1 6/1/2000 7/1/2000 3
1 7/1/2000 8/1/2000 1
Thanks in advance.
compressing number of rows using Hierarchical query
Anand Kothapeta, November 10, 2005 - 8:31 am UTC
If you think the above question is a new question thats alright not to answer at this point. But if you want to answer the question, I found a problem with the above query already. So I am still looking for a query that would work. Also if there is another column lets say, val2 and if it does have different values for the rows we are compressing, I want the resulting row should have value from the first row.
Thanks again
November 11, 2005 - 11:47 am UTC
see above, analytics would be my approach to collapse "adjacent" rows into a single row.
To "Anand Kothapeta from Hartford,CT"
Logan Palanisamy, November 11, 2005 - 10:44 pm UTC
Here is the answer with new KEY1 values. This is of course using one of Tom's techniques.
SQL> create table t (key1 number(2), start_date date, end_date date, val1 number(2));
Table created.
SQL> alter session set nls_date_format = 'dd/mm/yyyy';
Session altered.
SQL>
SQL> insert into t values (1, to_date('1/1/2000'), to_date('2/1/2000'), 1);
1 row created.
SQL> insert into t values (1, to_date('2/1/2000'), to_date('3/1/2000'), 1);
1 row created.
SQL> insert into t values (1, to_date('3/1/2000'), to_date('4/1/2000'), 2);
1 row created.
SQL> insert into t values (1, to_date('4/1/2000'), to_date('5/1/2000'), 2);
1 row created.
SQL> insert into t values (1, to_date('5/1/2000'), to_date('6/1/2000'), 2);
1 row created.
SQL> insert into t values (1, to_date('6/1/2000'), to_date('7/1/2000'), 3);
1 row created.
SQL> insert into t values (1, to_date('7/1/2000'), to_date('8/1/2000'), 1);
1 row created.
SQL>
SQL> insert into t values (2, to_date('11/1/2000'), to_date('12/1/2000'), 1);
1 row created.
SQL> insert into t values (2, to_date('12/1/2000'), to_date('13/1/2000'), 1);
1 row created.
SQL> insert into t values (2, to_date('13/1/2000'), to_date('14/1/2000'), 1);
1 row created.
SQL> insert into t values (2, to_date('14/1/2000'), to_date('15/1/2000'), 2);
1 row created.
SQL> insert into t values (2, to_date('15/1/2000'), to_date('16/1/2000'), 2);
1 row created.
SQL> insert into t values (2, to_date('16/1/2000'), to_date('17/1/2000'), 3);
1 row created.
SQL> insert into t values (2, to_date('17/1/2000'), to_date('18/1/2000'), 3);
1 row created.
SQL> insert into t values (2, to_date('18/1/2000'), to_date('19/1/2000'), 3);
1 row created.
SQL> insert into t values (2, to_date('19/1/2000'), to_date('20/1/2000'), 1);
1 row created.
SQL>
SQL> alter session set nls_date_format = 'dd-Mon-yyyy';
Session altered.
SQL> select * from t order by key1, start_date;
KEY1 START_DATE END_DATE VAL1
---------- ----------- ----------- ----------
1 01-Jan-2000 02-Jan-2000 1
1 02-Jan-2000 03-Jan-2000 1
1 03-Jan-2000 04-Jan-2000 2
1 04-Jan-2000 05-Jan-2000 2
1 05-Jan-2000 06-Jan-2000 2
1 06-Jan-2000 07-Jan-2000 3
1 07-Jan-2000 08-Jan-2000 1
2 11-Jan-2000 12-Jan-2000 1
2 12-Jan-2000 13-Jan-2000 1
2 13-Jan-2000 14-Jan-2000 1
2 14-Jan-2000 15-Jan-2000 2
2 15-Jan-2000 16-Jan-2000 2
2 16-Jan-2000 17-Jan-2000 3
2 17-Jan-2000 18-Jan-2000 3
2 18-Jan-2000 19-Jan-2000 3
2 19-Jan-2000 20-Jan-2000 1
16 rows selected.
SQL>
SQL> select key1, min(start_date) start_date, max(end_date) end_date, val1
2 from (
3 select key1, start_date, end_date, val1,
4 max(rn) over (partition by key1 order by start_date) grp
5 from (
6 select key1, start_date, end_date, val1,
7 case when lag(val1) over (partition by key1 order by start_date) <> val1 or
8 row_number() over (partition by key1 order by start_date) = 1
9 then row_number() over (partition by key1 order by start_date)
10 end rn
11 from t
12 )
13 )
14 group by key1, grp, val1
15 order by key1, start_date;
KEY1 START_DATE END_DATE VAL1
---------- ----------- ----------- ----------
1 01-Jan-2000 03-Jan-2000 1
1 03-Jan-2000 06-Jan-2000 2
1 06-Jan-2000 07-Jan-2000 3
1 07-Jan-2000 08-Jan-2000 1
2 11-Jan-2000 14-Jan-2000 1
2 14-Jan-2000 16-Jan-2000 2
2 16-Jan-2000 19-Jan-2000 3
2 19-Jan-2000 20-Jan-2000 1
8 rows selected.
Hierarchical query or one more table?
Dmytro, June 06, 2006 - 3:17 am UTC
Hello Tom! You was so helpful before, so here I am again :)
We have an application that registers veterynary clinics and doctors all around the country. Every clinic or doctor has an area in which it is supposed to give services. So we used the third-party dictionary which contains all territories in our country organized into hierarchical structure. We have three levels of hierarchy: region/district/town or village (a little more complicated, but it is of no matter for this question).
Table has next fields:
create table TERR
(
TER_ID NUMBER NOT NULL, - territory id
NAME_ID NUMBER NOT NULL, - id of territory name
TER_TER_ID NUMBER, - link to the territory 1 level higher
TER_LEVEL NUMBER NOT NULL, - level of territory
TER_TYPE NUMBER NOT NULL, - type of the territory
TER_CODE VARCHAR2(15) - territory unique code
)
and
create table TNAMES
(
NAME_ID NUMBER NOT NULL, - name id
NAME VARCHAR2(240), - territory name
)
Near 30 first-level territories, 700 second-level and 40000 of third level.
Our table, that contains clinics links to these tables by TER_ID. The task is to create search function for finding clinics and doctors around the country using different filters. Using your great idea about using sys_context to create dynamic searches with varying number of filters, I still need to add one more filter - by territory.
So, I need to find all clinics in given territory and all underlying. In one of our previous applications, where we have our own hierarchical dictionary, we created table TERR_LINKS with fields PARENT and CHILD and filled it in the way, where every territory has at least one record, where it was parent and child at the same time.
So our filter was as simpe as:
...AND clinics.ter_ter_id IN (SELECT child
FROM TERR_LINKS
WHERE parent = p_ter_id)
But now there are some problems, realising this approach, because we can't change the dictionary (add tables in its schema) ourselves (but can add this table in our schema) and because data in the dictionary potentially could be updated through third-party application, so we'll need keep track of this changes and update our table too.
Second approach I'm thinking of now is something like this:
...AND clinics.ter_ter_id IN
(SELECT t.ter_id
FROM terr t
START WITH t.ter_ter_id = p_ter_id
CONNECT BY PRIOR t.ter_id = t.ter_ter_id
UNION ALL
SELECT p_ter_id FROM dual)
I test this thing on one of our reports and it showed 303 sec against 290 in the variant with additional 'links' table. Not so big difference, but... Few times before, I have some strange results using hierarchical queries - the plan went crazy and queries were running for hours and hours, so I'm a bit confused if it happens again. Also, for now I have tested the perfomance only on few queries and can't say how much the difference will be on more complicated reports and search-functions.
Can you give few words on what approach, you'll better use in this situation, maybe something completely new, that I haven't think of.
In any case, want to say, that I admire your great work. This site is a little miracle for Oracle users around the world.
Thanks
Multiple records within a hierarchy
A reader, October 10, 2006 - 11:58 am UTC
Is it possible to get multiple records of a particular employee within a
hierarchy in specific cases?
I have the following table structure.
create table EMPINFO
( c_STATUS VARCHAR2(2),
c_GROUP VARCHAR2(10),
c_SYSID VARCHAR2(10),
c_SYSTEM VARCHAR2(10),
c_NAME VARCHAR2(40),
c_ID VARCHAR2(10),
c_MGRID VARCHAR2(10),
c_MGRNAME VARCHAR2(40)
);
Typical Data is
insert into EMPINFO VALUES ('A','HR','','','JASON BICKER','0000001','','');
insert into EMPINFO VALUES ('A','HR','','','NANCY
WALTER','0400001','0000001','JASON BICKER');
insert into EMPINFO VALUES ('','MF','NAN3005','WIN','NANCY
WALTER','0400001','','');
insert into EMPINFO VALUES ('','MF','NAN3005','UNIX','NANCY
WALTER','0400001','','');
insert into EMPINFO VALUES ('A','HR','','','ADAM
BRYAN','0400002','0000001','JASON BICKER');
insert into EMPINFO VALUES ('','MF','BRY0034','WIN','ADAM
BRYAN','0400002','','');
insert into EMPINFO VALUES ('A','HR','','','STING
CORY','0400003','0400002','ADAM BRYAN');
insert into EMPINFO VALUES ('','MF','STI4040','UNIX','STING
CORY','0400003','','');
For example I want to display all records of NANCY WALTER. The c_MGRID is blank
for 2nd and 3rd record of NANCY WALTER. Similar structure will follow for other
records as well.
Regards,
Rao
How to find data causing ORA-01436: CONNECT BY loop in user data
Shivdeep Modi, March 06, 2007 - 7:10 pm UTC
Hi Tom,
How do we find the data causing ORA-01436
create table asd( parent number, child number);
insert into asd values(1,2);
insert into asd values(2,1);
insert into asd values(1,3);
/NCLDBA/NV00 > select parent,child
2 from asd
3 start with parent=1
4 connect by prior child = parent;
ERROR:
ORA-01436: CONNECT BY loop in user data
no rows selected
/NCLDBA/NV00 >
Can we get (1,2) (2,1) etc.
Regards,
Shivdeep Modi
March 07, 2007 - 10:06 am UTC
Well, in 10g, you can NOCYCLE:
ops$tkyte%ORA10GR2> select parent,child, connect_by_iscycle
2 from asd
3 start with parent=1
4 connect by NOCYCLE prior child = parent;
PARENT CHILD CONNECT_BY_ISCYCLE
---------- ---------- ------------------
1 2 0
2 1 1
1 3 0
1 3 0
In 9i, you can use single row fetching:
ops$tkyte%ORA9IR2> begin
2 for x in (
3 select level l,parent,child
4 from asd
5 start with parent=1
6 connect by prior child = parent )
7 loop
8 dbms_output.put_line( to_char( x.l, '9999' ) || ') ' ||
9 to_char( x.parent, '99999' ) || to_char(x.child,'99999') );
10 end loop;
11 end;
12 /
1) 1 2
2) 2 1
3) 1 2
begin
*
ERROR at line 1:
ORA-01436: CONNECT BY loop in user data
ORA-06512: at line 2
How to find data causing ORA-01436: CONNECT BY loop in user data
Shivdeep Modi, March 08, 2007 - 5:25 am UTC
Thanks Tom,
10g stuff is good, but 9i requires more work.
If in Oracle9i database, I've got something like.
insert into asd values(1,2);
insert into asd values(1,3);
insert into asd values(2,1);
insert into asd values(3,4);
insert into asd values(4,5);
insert into asd values(5,4);
I need to fix/remove (1,2) (2,1) to find (4,5) (5,4). I don't think we can find all the cyclic rows in a single SQL|PL/SQL or can we?
Regards,
Shivdeep
Hierarchical Queries
Hemal, April 20, 2007 - 11:34 am UTC
Hello Tom,
I have writtern ORACLE 10G PL/SQL Stored Procedure which has some "Hierarchical Queries".
I want to create same Stored Procedure in MS SQL SERVER 2005.
Do I need to perform any changes in the "Hierarchical Queries".
( I am a Oracle PL/SQL Developer.But current project needs to create same stored procedures in MS SQL SERVER 2005).
Please Advice me.
Thanks and Best Regards
-Hemal
April 20, 2007 - 1:48 pm UTC
you'll have to wait for MS SQL SERVER 2020 (hindsight :)
you'll need to sort of figure out how to do a connect by in sqlserver, procedurally I think will be their answer.
Substitute for NOCYCLE in 9i
Roy, June 15, 2007 - 2:32 am UTC
Hi Tom,
We need to write a query to get the hierarchy among the financial advisers for our client. We wrote this:
SELECT parent_fa_no, finadv_no, LEVEL, --CONNECT_BY_ISCYCLE,
SYS_CONNECT_BY_PATH(itr_no, '/')
FROM Finadvtab
WHERE status = 'LIVE'
START WITH parent_fa_no = 100
CONNECT BY /*NOCYCLE */ PRIOR finadv_no = parent_fa_no
But, we faced this error:
ORA-01436: CONNECT BY loop in user data.
We are on 9i and we need to do what NOCYCLE and CONNECT_BY_ISCYCLE pseudocolumn can do in 10g.
Could you please suggest a workaround for this?
Thanks.
June 15, 2007 - 7:46 am UTC
not without a full understanding of your data model.
Is there anything you can put into your connect by to detect that you are entering a cycle - intimate knowledge of your data and how it relates to itself would be required (eg: you need to answer this, can you logically look at a row and say "stop here")
Roy, June 15, 2007 - 2:37 am UTC
Sorry the query is rather:
SELECT parent_fa_no, finadv_no, LEVEL, --CONNECT_BY_ISCYCLE,
SYS_CONNECT_BY_PATH(finadv_no, '/')
FROM Finadvtab
WHERE status = 'LIVE'
START WITH parent_fa_no = 100
CONNECT BY /*NOCYCLE */ PRIOR finadv_no = parent_fa_no
Thanks.
Substitute for NOCYCLE in 9i
Roy, June 15, 2007 - 11:41 am UTC
Hi Tom,
....you need to answer this, can you logically look at a row and say "stop here")
Yes, we have a field (say, Subadv_count) that gives us the number of sub-advisers for a given finadv_no. We are happy to stop when this count becomes zero, i.e. when we have reached the leaf. Until then, we need to traverse down the hierarchy.
Is there anything you can put into your connect by to detect that you are entering a cycle...
Does my previous answer somehow address this too? I couldn't catch you here.
Thanks.
June 15, 2007 - 12:02 pm UTC
connect by ...... and subadv_count > 0;
that'll stop connecting when subadv_count is not greater than zero
Substitute for NOCYCLE in 9i
Roy, June 15, 2007 - 12:17 pm UTC
In that case, will it not prevent us from picking up the advisers at the leaf of the hierarchy? Did you mean rather this?
connect by ... and prior subadv_count > 0;
Well, we tried both with & without 'prior', still facing the error. May be, we are falling short somewhere on the information regarding "...how it relates to itself...".
Thanks.
June 15, 2007 - 12:32 pm UTC
ok, connect by prior whatever > 0;
yes.
put together an example that is failing (create table, insert intos) and it'll likely become obvious what else is missing
Substitute for NOCYCLE in 9i
Roy, June 15, 2007 - 12:26 pm UTC
Tom,
Well, we have 2 more fields in each row, which are related to the hierarchy:
MasterAdv_no: The adviser at the root of the hierarchy.
HierarchyPosition: Similar to Oracle's LEVEL keyword.
Thanks.
June 15, 2007 - 12:33 pm UTC
now, use your knowledge of your data and your knowledge of connect by and figure out "what condition makes us stop"
Vow you are Back
A reader, June 20, 2007 - 3:43 am UTC
Tom Thanks for coming back and Staying Alive.
Please Keep it up. You dont know how these 5 days have been for us without AskTOM our Metalink 24/7 support.
Staying Alive Staying Alive .......
Substitute for NOCYCLE in 9i
Roy, June 20, 2007 - 3:43 am UTC
So, that's the way it is....
SELECT parent_fa_no, finadv_no, LEVEL, --CONNECT_BY_ISCYCLE,
SYS_CONNECT_BY_PATH(finadv_no, '/')
FROM Finadvtab
WHERE status = 'LIVE'
START WITH parent_fa_no = 100
CONNECT BY /*NOCYCLE */ PRIOR finadv_no = parent_fa_no
AND PRIOR MasterAdv_no = MasterAdv_no
AND PRIOR Subadv_count > 0
AND PRIOR HierarchyPosition < HierarchyPosition;
Thanks Tom. This solved the problem. The way you drive us to the solution is amazing.......
Many thanks again.
how to store .pdf and .txt files in oracle database
Rishipal, June 20, 2007 - 7:34 am UTC
Hi Tom,
This is Rishipal, and want to store .pdf and .txt files in oracle databse. I am querying u very first time I visited your site and find something valuable.looking u forward
Thanks........
June 20, 2007 - 10:45 am UTC
Uncontrolled chain reaction with CONNECT BY
Roy, June 22, 2007 - 10:08 am UTC
Hi Tom,
I am sure, there can be no-one else than you who can tell us a solution for this.
Basically, we have a table called payment_details as created & populated below:
CREATE TABLE payment_details
(start_date DATE,
end_date DATE,
pay_amount NUMBER(12,2)
);
INSERT INTO payment_details
SELECT trunc(add_months(SYSDATE,-24)), trunc(add_months(SYSDATE,-6)), 24.50
FROM dual
UNION ALL
SELECT trunc(add_months(SYSDATE,-30)),trunc(add_months(SYSDATE,-12)), 32.30
FROM dual;
Now, we need to write a query that would display all the payments done for each of the records in the above table in this format:
Payment_date, Pay_amount
The frequency of payment is say, monthly. So, for the first record in payment_details, it should display like below:
Payment_date Pay_amount
22/06/2005 24.50
22/07/2005 24.50
22/08/2005 24.50
.....
.....
22/12/2006 24.50
Similarly, for the 2nd record too. So, we need to expand one row in payment_details into multiple rows, but "how many" is not a static value and is dependent on the duration (end_date - start_date). So, we tried this query:
SELECT add_months(start_date,LEVEL-1) paid_date, --start_date, end_date, pay_amount
FROM payment_details, dual
CONNECT BY LEVEL < months_between(end_date,start_date);
But, this query works like an atomic bomb!!! It grows exponentially!! We tried a simple case:
SELECT add_months(start_date,LEVEL-1) paid_date, --start_date, end_date, pay_amount
FROM payment_details, dual
CONNECT BY LEVEL < 3 --months_between(end_date,start_date);
This creates 1 row for 22/06/2005, but 2 rows for 22/07/2005 (for the 1st row in payment_details)
When we do this:
SELECT add_months(start_date,LEVEL-1) paid_date, --start_date, end_date, pay_amount
FROM payment_details, dual
CONNECT BY LEVEL < 4 --months_between(end_date,start_date);
it creates 1 row for 22/06/2005, 2 rows for 22/07/2005 and 4 rows for 22/08/2005.
Could you please suggest a workaround for this? Obviously, we can add DISTINCT to the above query to get one row for each month's payment. But, that would be a drastically bad idea, I guess. Using dual this way seems to be "carcinogenic" for SQL!!
June 22, 2007 - 5:04 pm UTC
ops$tkyte%ORA10GR2> select start_date, end_date, pay_amount, ceil( months_between(end_date,start_date)) rws
2 from payment_details
3 /
START_DAT END_DATE PAY_AMOUNT RWS
--------- --------- ---------- ----------
22-JUN-05 22-DEC-06 24.5 18
22-DEC-04 22-JUL-06 32.3 19
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> select start_date, end_date, add_months(start_date,level-1) DT, pay_amount,
2 ceil( months_between(end_date,start_date)) rws
3 from payment_details
4 connect by prior start_date = start_date and prior end_date = end_date and prior pay_amount = pay_amount
5 and level <= ceil( months_between(end_date,start_date))
6 AND PRIOR dbms_random.string ('p', 10) IS NOT NULL
7 order by 1, 2, 5
8 /
START_DAT END_DATE DT PAY_AMOUNT RWS
--------- --------- --------- ---------- ----------
22-DEC-04 22-JUL-06 22-DEC-04 32.3 19
22-DEC-04 22-JUL-06 22-JAN-05 32.3 19
22-DEC-04 22-JUL-06 22-JUN-06 32.3 19
22-DEC-04 22-JUL-06 22-MAY-06 32.3 19
22-DEC-04 22-JUL-06 22-APR-06 32.3 19
22-DEC-04 22-JUL-06 22-MAR-06 32.3 19
22-DEC-04 22-JUL-06 22-FEB-06 32.3 19
22-DEC-04 22-JUL-06 22-JAN-06 32.3 19
22-DEC-04 22-JUL-06 22-DEC-05 32.3 19
22-DEC-04 22-JUL-06 22-NOV-05 32.3 19
22-DEC-04 22-JUL-06 22-OCT-05 32.3 19
22-DEC-04 22-JUL-06 22-SEP-05 32.3 19
22-DEC-04 22-JUL-06 22-AUG-05 32.3 19
22-DEC-04 22-JUL-06 22-JUL-05 32.3 19
22-DEC-04 22-JUL-06 22-JUN-05 32.3 19
22-DEC-04 22-JUL-06 22-MAY-05 32.3 19
22-DEC-04 22-JUL-06 22-APR-05 32.3 19
22-DEC-04 22-JUL-06 22-MAR-05 32.3 19
22-DEC-04 22-JUL-06 22-FEB-05 32.3 19
22-JUN-05 22-DEC-06 22-OCT-06 24.5 18
22-JUN-05 22-DEC-06 22-NOV-06 24.5 18
22-JUN-05 22-DEC-06 22-AUG-06 24.5 18
22-JUN-05 22-DEC-06 22-JUL-06 24.5 18
22-JUN-05 22-DEC-06 22-JUN-06 24.5 18
22-JUN-05 22-DEC-06 22-MAY-06 24.5 18
22-JUN-05 22-DEC-06 22-APR-06 24.5 18
22-JUN-05 22-DEC-06 22-MAR-06 24.5 18
22-JUN-05 22-DEC-06 22-FEB-06 24.5 18
22-JUN-05 22-DEC-06 22-JAN-06 24.5 18
22-JUN-05 22-DEC-06 22-DEC-05 24.5 18
22-JUN-05 22-DEC-06 22-NOV-05 24.5 18
22-JUN-05 22-DEC-06 22-OCT-05 24.5 18
22-JUN-05 22-DEC-06 22-SEP-05 24.5 18
22-JUN-05 22-DEC-06 22-AUG-05 24.5 18
22-JUN-05 22-DEC-06 22-JUL-05 24.5 18
22-JUN-05 22-DEC-06 22-JUN-05 24.5 18
22-JUN-05 22-DEC-06 22-SEP-06 24.5 18
37 rows selected.
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> with data
2 as
3 (select level l
4 from (select max( ceil( months_between(end_date,start_date)) ) rws from payment_details)
5 connect by level <= rws
6 )
7 select start_date, end_date, add_months(start_date,l-1) DT, pay_amount,
8 ceil( months_between(end_date,start_date)) rws
9 from payment_details, data
10 where l <= ceil( months_between(end_date,start_date))
11 order by 1, 2, 5
12 /
START_DAT END_DATE DT PAY_AMOUNT RWS
--------- --------- --------- ---------- ----------
22-DEC-04 22-JUL-06 22-DEC-04 32.3 19
22-DEC-04 22-JUL-06 22-MAY-06 32.3 19
22-DEC-04 22-JUL-06 22-APR-06 32.3 19
22-DEC-04 22-JUL-06 22-MAR-06 32.3 19
22-DEC-04 22-JUL-06 22-FEB-06 32.3 19
22-DEC-04 22-JUL-06 22-JAN-06 32.3 19
22-DEC-04 22-JUL-06 22-DEC-05 32.3 19
22-DEC-04 22-JUL-06 22-NOV-05 32.3 19
22-DEC-04 22-JUL-06 22-OCT-05 32.3 19
22-DEC-04 22-JUL-06 22-SEP-05 32.3 19
22-DEC-04 22-JUL-06 22-AUG-05 32.3 19
22-DEC-04 22-JUL-06 22-JUL-05 32.3 19
22-DEC-04 22-JUL-06 22-JUN-05 32.3 19
22-DEC-04 22-JUL-06 22-MAY-05 32.3 19
22-DEC-04 22-JUL-06 22-APR-05 32.3 19
22-DEC-04 22-JUL-06 22-MAR-05 32.3 19
22-DEC-04 22-JUL-06 22-FEB-05 32.3 19
22-DEC-04 22-JUL-06 22-JAN-05 32.3 19
22-DEC-04 22-JUL-06 22-JUN-06 32.3 19
22-JUN-05 22-DEC-06 22-JUL-06 24.5 18
22-JUN-05 22-DEC-06 22-JUN-05 24.5 18
22-JUN-05 22-DEC-06 22-SEP-06 24.5 18
22-JUN-05 22-DEC-06 22-JAN-06 24.5 18
22-JUN-05 22-DEC-06 22-JUN-06 24.5 18
22-JUN-05 22-DEC-06 22-DEC-05 24.5 18
22-JUN-05 22-DEC-06 22-OCT-06 24.5 18
22-JUN-05 22-DEC-06 22-NOV-05 24.5 18
22-JUN-05 22-DEC-06 22-MAY-06 24.5 18
22-JUN-05 22-DEC-06 22-OCT-05 24.5 18
22-JUN-05 22-DEC-06 22-AUG-06 24.5 18
22-JUN-05 22-DEC-06 22-SEP-05 24.5 18
22-JUN-05 22-DEC-06 22-APR-06 24.5 18
22-JUN-05 22-DEC-06 22-AUG-05 24.5 18
22-JUN-05 22-DEC-06 22-NOV-06 24.5 18
22-JUN-05 22-DEC-06 22-JUL-05 24.5 18
22-JUN-05 22-DEC-06 22-MAR-06 24.5 18
22-JUN-05 22-DEC-06 22-FEB-06 24.5 18
37 rows selected.
CONNECT BY
Roy, June 22, 2007 - 12:31 pm UTC
Oh, and I see, dual is not required and the following works similar to that with dual:
SELECT add_months(start_date,LEVEL-1) paid_date, --start_date, end_date, pay_amount
FROM payment_details
CONNECT BY LEVEL < months_between(end_date,start_date);
Thanks.
June 22, 2007 - 5:12 pm UTC
that does not work, see above
CONNECT BY
Roy, June 23, 2007 - 4:47 am UTC
Oh my god!!! I am literally spellbound!!!
Tom, you are a genius!!! That's why you are the guru of all gurus!!! And, that's why, I am a disciple of you!!!
I wish I can meet you and talk to you one day!!!
Many Thanks.
June 23, 2007 - 9:05 am UTC
I learned everything I know from others - just keep hanging out in the online communities..
A reader, July 25, 2007 - 6:25 am UTC
Hi,
Please help to write Hirearichal query
SELECT XLEVEL1_NAME,XLEVEL2_NAME, XLEVEL3_NAME
FROM
CATEGORY
XLEVEL1_NAME XLEVEL2_NAME XLEVEL3_NAME
Product
Product Hardware
Product Hardware Networking
CA
CA XXXX
CA XXXX YYYY
I want to write a query
If XLEVEL1_NAME is not null(Root) then return parnet record i.e Product
If XLEVEL1_NAME and XLEVEL2_NAME is not null then return the child record of 2nd row i.e.Hardware
If XLEVEL1_NAME and XLEVEL2_NAME and XLEVEL2_NAME not null then return child record of 3 row i.e.Networking
I want results like this
XLEVEL1_NAME XLEVEL2_NAME XLEVEL3_NAME level1 level 2
Product 1 1
Hardware 1 2
Networking 1 3
CA 2 1
XXX 2 2
YYYY 2 3
Thanks,
MM
July 26, 2007 - 9:11 am UTC
no create
no inserts
NO LOOK
Tuning Hierarchical Query
Chris, August 30, 2007 - 10:48 am UTC
Tom,
I have a rather large query using analytic functions, subqueries, and a WITH clause. The query runs in a couple minutes which considering the millions of records its processing and the complex analytics being performed is just fine. A general structure is like this:
WITH q1 AS (),
q2 AS ()
SELECT x, y, z
FROM q1, q2
WHERE q1.something = q2.something
you get the idea. q1 and q2 have some analytics and subqueries buried in them. My problem now comes when I want to use a hierarchical query on that result set. The above query only returns 1100 rows, so logically in my mind I'm thinking that when I wrap it like this:
SELECT x, y, z FROM ( above query )
START WITH ...
CONNECT BY PRIOR ...
it should run pretty quick. The problem is that it does not and when I look at the explain plan, it is actually showing the inner queries 3 times. I was hoping to see the inner query get performed once, then the hierarchical "stuff" get performed on a materialized version of that. How can I force the "START WITH ... CONNECT BY ..." to operate on the 1100 row results without re-executing the inner pieces of the query multiple times?
September 04, 2007 - 5:23 pm UTC
with q1 as (),
q2 as (),
q3 as (above query)
select ... from q3 start with....
Helena Marková, September 05, 2007 - 2:47 am UTC
union and hierarchical queries
Michal Pravda, January 04, 2008 - 1:57 am UTC
Hello Tom,
I've tried to write a query which returns whether two people are in a chain of command or not. It behaves kind of strange: when I try one way (is A subordinate of B) and then the other (is B subordinate of A) then everything is OK. But when I try to union both ways in one query, I get an error.
example:
select * from v$version;
1 Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
2 PL/SQL Release 10.2.0.3.0 - Production
3 CORE 10.2.0.3.0 Production
4 TNS for IBM/AIX RISC System/6000: Version 10.2.0.3.0 - Productio
5 NLSRTL Version 10.2.0.3.0 - Production
select empno, ename, mgr from emp;
1 7369 SMITH 7902
2 7499 ALLEN 7698
3 7521 WARD 7698
4 7566 JONES 7839
5 7654 MARTIN 7698
6 7698 BLAKE 7839
7 7782 CLARK 7839
8 7788 SCOTT 7566
9 7839 KING
10 7844 TURNER 7698
11 7876 ADAMS 7788
12 7900 JAMES 7698
13 7902 FORD 7566
14 7934 MILLER 7782
select * from emp
where ename = 'KIN';
<empty set>
----------------------
select decode(count(*) , 0, 'NO', 'YES') in_chain
from (
select ename
from emp
start with ename = 'SCOTT'
connect by mgr = prior empno
)
where ename = 'KIN';
in_chain NO --KIN is not SCOTT's subordinate
select decode(count(*) , 0, 'NO', 'YES') in_chain
from (
select ename
from emp
start with ename = 'SCOTT'
connect by prior mgr = empno
)
where ename = 'KIN';
in_chain NO --KIN is not SCOTT's superordinate
So far, so good. But:
select decode(count(*) , 0, 'NO', 'YES') in_chain
from (
select ename
from emp
start with ename = 'SCOTT'
connect by prior mgr = empno
union
select ename
from emp
start with ename = 'SCOTT'
connect by mgr = prior empno
)
where ename = 'KIN';
in_chain YES --KIN is either SCOTT's superordinate or subordinate
Could you tell me where the error is?
January 04, 2008 - 11:46 am UTC
could not reproduce in 8i, 9i or 10g...
ops$tkyte%ORA10GR2> create table emp as select * from scott.emp;
Table created.
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> select decode(count(*) , 0, 'NO', 'YES') in_chain
2 from (
3 select ename
4 from emp
5 start with ename = 'SCOTT'
6 connect by mgr = prior empno
7 )
8 where ename = 'KIN';
IN_
---
NO
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> select decode(count(*) , 0, 'NO', 'YES') in_chain
2 from (
3 select ename
4 from emp
5 start with ename = 'SCOTT'
6 connect by prior mgr = empno
7 )
8 where ename = 'KIN';
IN_
---
NO
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> select decode(count(*) , 0, 'NO', 'YES') in_chain
2 from (
3 select ename
4 from emp
5 start with ename = 'SCOTT'
6 connect by prior mgr = empno
7 union
8 select ename
9 from emp
10 start with ename = 'SCOTT'
11 connect by mgr = prior empno
12 )
13 where ename = 'KIN';
IN_
---
NO
even stranger
Michal Pravda, January 07, 2008 - 3:29 am UTC
Well, if it works well for you then you can't probably help me.
I was able only to further the bizarreness of the example:
select *
from (
select ename
from emp
start with ename = 'SCOTT'
connect by prior mgr = empno
)
where 0=1;
<empty set>
select *
from (
select ename
from emp
start with ename = 'SCOTT'
connect by prior mgr = empno
union
select '' ename from dual
)
where 0=1;
ename
-----
SCOTT
Basically it's the same as before, but the weirdness can be clearly seen, I think.
January 07, 2008 - 8:06 am UTC
that is not a cut and paste
I would suggest setting autotrace on and posting the
a) CUT AND PASTE from splplus
b) with the query plans
sqlplus cut&paste
Michal Pravda, January 11, 2008 - 2:55 am UTC
I have included DDL to be sure. Cut&Paste crippled some non-ascii characters, but it isn't relevant for this example. I included two selects. One with only the hierarchical query, and one with the hierarchical query 'unioned' with an empty set. The former behaves correctly, the latter is not as you can see.
Thank you for your help.
pravda_m@ISD> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
PL/SQL Release 10.2.0.3.0 - Production
CORE 10.2.0.3.0 Production
TNS for IBM/AIX RISC System/6000: Version 10.2.0.3.0 - Productio
NLSRTL Version 10.2.0.3.0 - Production
pravda_m@ISD> drop table emp_test;
Tabulka zru¿ena.
pravda_m@ISD> create table emp_test(
2 empno number primary key,
3 ename varchar2(50),
4 job varchar2(50),
5 mgr number);
Tabulka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7369, 'SMITH', 'CLERK', 7902);
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7499, 'ALLEN', 'SALESMAN', 7698);
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7521, 'WARD', 'SALESMAN', 7698);
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7566, 'JONES', 'MANAGER', 7839);
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7654, 'MARTIN', 'SALESMAN', 7698)
;
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7698, 'BLAKE', 'MANAGER', 7839);
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7782, 'CLARK', 'MANAGER', 7839);
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7788, 'SCOTT', 'ANALYST', 7566);
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7839, 'KING', 'PRESIDENT', null);
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7844, 'TURNER', 'SALESMAN', 7698)
;
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7876, 'ADAMS', 'CLERK', 7788);
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7900, 'JAMES', 'CLERK', 7698);
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7902, 'FORD', 'ANALYST', 7566);
1 øádka vytvoøena.
pravda_m@ISD> insert into emp_test(empno, ename, job, mgr) values (7934, 'MILLER', 'CLERK', 7782);
1 øádka vytvoøena.
pravda_m@ISD> commit;
Potvrzení dokonèeno.
pravda_m@ISD> set autotrace on
pravda_m@ISD> select *
2 from (
3 select ename
4 from emp_test
5 start with ename = 'SCOTT'
6 connect by prior mgr = empno
7 /*union
8 select null ename from dual where 0=1
9 */
10 )
11 where 0=1;
nebyly vybrány ¿ádné øádky
Plán provedení
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=0 Card=1 Bytes=77)
1 0 FILTER
2 1 VIEW (Cost=1 Card=1 Bytes=77)
3 2 CONNECT BY (WITH FILTERING)
4 3 TABLE ACCESS (FULL) OF 'EMP_TEST' (TABLE) (Cost=3 Card=1 Bytes=180)
5 3 NESTED LOOPS
6 5 BUFFER (SORT)
7 6 CONNECT BY PUMP
8 5 TABLE ACCESS (BY INDEX ROWID) OF 'EMP_TEST' (TABLE) (Cost=1 Card=1 Bytes=103)
9 8 INDEX (UNIQUE SCAN) OF 'SYS_C0027225' (INDEX (UNIQUE)) (Cost=1 Card=1)
10 3 TABLE ACCESS (FULL) OF 'EMP_TEST' (TABLE) (Cost=3 Card=14 Bytes=1442)
Statistiky
----------------------------------------------------------
10 recursive calls
0 db block gets
24 consistent gets
0 physical reads
0 redo size
155 bytes sent via SQL*Net to client
236 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
pravda_m@ISD> select *
2 from (
3 select ename
4 from emp_test
5 start with ename = 'SCOTT'
6 connect by prior mgr = empno
7 union
8 select null ename from dual where 0=1
9 )
10 where 0=1;
ENAME
--------------------------------------------------
SCOTT
Plán provedení
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=2 Card=2 Bytes=154)
1 0 VIEW (Cost=2 Card=2 Bytes=154)
2 1 SORT (UNIQUE) (Cost=2 Card=2 Bytes=103)
3 2 UNION-ALL
4 3 CONNECT BY (WITH FILTERING)
5 4 TABLE ACCESS (FULL) OF 'EMP_TEST' (TABLE) (Cost=3 Card=1 Bytes=180)
6 4 FILTER
7 6 NESTED LOOPS
8 7 BUFFER (SORT)
9 8 CONNECT BY PUMP
10 7 TABLE ACCESS (BY INDEX ROWID) OF 'EMP_TEST' (TABLE) (Cost=1 Card=1 Bytes=103)
11 10 INDEX (UNIQUE SCAN) OF 'SYS_C0027225' (INDEX (UNIQUE)) (Cost=1 Card=1)
12 4 TABLE ACCESS (FULL) OF 'EMP_TEST' (TABLE) (Cost=3 Card=14 Bytes=1442)
13 3 FILTER
14 13 FAST DUAL (Cost=2 Card=1)
Statistiky
----------------------------------------------------------
10 recursive calls
0 db block gets
31 consistent gets
0 physical reads
0 redo size
227 bytes sent via SQL*Net to client
277 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
4 sorts (memory)
0 sorts (disk)
1 rows processed
pravda_m@ISD>
It looks to me that filter operation moved from line "1" to line "6" in the explain plan. My guess is that that is what is wrong, but I don't know why.
January 11, 2008 - 7:42 am UTC
I filed
Bug No: 6743574
Hierarchical Tree
Dulal, February 04, 2008 - 11:27 pm UTC
I have a table with data as following.
SL_No (PK) Ref_No TIN
---------- ------ --------
11 Ref-11 52001
22 Ref-12 52006
33 Ref-56 65009
44 Ref-86 78004
55 Ref-57 52006
66 Ref-61 99011
77 Ref-96 52001
88 Ref-33 23055
99 Ref-26 65008
I want a Hierarchical Tree like this to use in Oracle Forms 10gR2 on windows xp and Oracle10g database.
23055
| |-Ref-33
|
52001
| |-Ref-11
| |-Ref-96
|
52006
| |-Ref-12
| |-Ref-57
|
65008
|
|
.......................
.......................
etc.
---scripts--------------
create table htree_test
(
sl_no number(2),
ref_no varchar2(10),
tin varchar2(5));
/
insert into htree_test values (11,'Ref-11','52001');
insert into htree_test values (22,'Ref-12','52006');
insert into htree_test values (33,'Ref-56','65009');
insert into htree_test values (44,'Ref-86','78004');
insert into htree_test values (55,'Ref-57','52006');
insert into htree_test values (66,'Ref-61','99011');
insert into htree_test values (77,'Ref-96','52001');
insert into htree_test values (88,'Ref-33','23055');
insert into htree_test values (99,'Ref-26','65008');
commit;
/
Pls help me.
Best regards.
Dulal
February 05, 2008 - 6:59 am UTC
I haven't touched forms since 1995... please try otn.oracle.com -> discussion forums.
Hierarchical Tree
Dulal, February 06, 2008 - 1:13 am UTC
Hi,
Thanks for your quick reply.
But Sir, I want the query syntax only.
e.g.
SELECT 1, LEVEL, TIN, .......................
Pls help.
February 06, 2008 - 7:51 am UTC
umm,
given that I rather don't know what output you need for the forms tree widget - you would be best served by finding that out first - no?
ops$tkyte%ORA10GR2> select tin, ref_no, grouping(tin), grouping(ref_no)
2 from t
3 group by rollup(tin,ref_no)
4 order by tin, grouping(ref_no) DESC
5 /
TIN REF_NO GROUPING(TIN) GROUPING(REF_NO)
----- ---------- ------------- ----------------
23055 0 1
23055 Ref-33 0 0
52001 0 1
52001 Ref-96 0 0
52001 Ref-11 0 0
52006 0 1
52006 Ref-12 0 0
52006 Ref-57 0 0
65008 0 1
65008 Ref-26 0 0
65009 0 1
65009 Ref-56 0 0
78004 0 1
78004 Ref-86 0 0
99011 0 1
99011 Ref-61 0 0
1 1
17 rows selected.
ops$tkyte%ORA10GR2> select decode(gref_no,1,tin) newtin, ref_no
2 from (
3 select tin, ref_no, grouping(tin), grouping(ref_no) gref_no
4 from t
5 group by rollup(tin,ref_no)
6 )
7 order by tin, gref_no DESC
8 /
NEWTI REF_NO
----- ----------
23055
Ref-33
52001
Ref-96
Ref-11
52006
Ref-12
Ref-57
65008
Ref-26
65009
Ref-56
78004
Ref-86
99011
Ref-61
17 rows selected.
A reader, February 25, 2008 - 5:20 am UTC
Connect By Prior
Bhushan, March 27, 2008 - 9:13 pm UTC
Hi Tom,
I learnt a lot from this site, thank you for hosting it.
Could you please help me understand what is the difference between the queries pasted below.I am just trying to understand the concept so practically the data might not make sense. Create/insert below as you insist everytime ;)
create table COUNTER
(
X INTEGER,
Y VARCHAR2(10),
MGR NUMBER(2)
)
INSERT INTO counter VALUES (1,'A',0);
INSERT INTO counter VALUES (2,'B',1);
INSERT INTO counter VALUES (3,'C',1);
INSERT INTO counter VALUES (4,'D',2);
INSERT INTO counter VALUES (5,'E',3);
INSERT INTO counter VALUES (6,'F',2);
INSERT INTO counter VALUES (7,'G',4);
INSERT INTO counter VALUES (8,'H',6);
commit;
Here are the queries
------------------------------
SELECT x,y,mgr,LEVEL FROM (SELECT x,y,mgr FROM counter )
START WITH mgr=0 CONNECT BY PRIOR x=mgr
ORDER BY mgr
* This gives me the result what i "thought" Connect By is built for, however when I change x=mgr in the clause to mgr=x it gives me a totally different output.
----------------------------------------------------
Also,
Do not understand how Start With clause works
SELECT x,y,mgr,LEVEL FROM (SELECT x,y,mgr FROM counter )
/*START WITH mgr=0*/ CONNECT BY PRIOR x=mgr
ORDER BY mgr
Awaiting your reply.
Cheers!!!
Bhushan
March 30, 2008 - 9:12 am UTC
... This gives me the result what i "thought" Connect By is built for, however
when I change x=mgr in the clause to mgr=x it gives me a totally different
output.
....
Let us hope so! Because you changed:
connect by (PRIOR X)=MGR
into
connect by (PRIOR MGR)=X
by just moving X and MGR, you didn't move the "PRIOR" which is a modifier to the next attribute in the query....
The query:
SELECT x,y,mgr,LEVEL FROM (SELECT x,y,mgr FROM counter )
START WITH mgr=0 CONNECT BY PRIOR x=mgr
ORDER BY mgr
starts by finding all rows such that "mgr=0", of which there is a single record.
ops$tkyte%ORA11GR1> select * from counter where mgr=0;
X Y MGR
---------- ---------- ----------
1 A 0
It then applies the connect by TO EACH RECORD RETURNED BY THE START WITH. So, once this start with record is "output", it becomes the "prior" record. So, we take "X" from this prior record
ops$tkyte%ORA11GR1> select x from counter where mgr = 0;
X
----------
1
and use that value to retrieve the next level of records by MGR:
ops$tkyte%ORA11GR1> select * from counter where (select x from counter where mgr=0) = mgr;
X Y MGR
---------- ---------- ----------
2 B 1
3 C 1
so, that start with record is connected to these two records. Now, they each in turn become the "prior" record, so we'll take X=2 to find any MGR=2 records and output them (whence they themselves become the prior record and so on)
resulting in the hierarchy:
ops$tkyte%ORA11GR1> SELECT rpad('*',2*level,'*') data, x,y,mgr,LEVEL
2 FROM (SELECT x,y,mgr FROM counter )
3 START WITH mgr=0 CONNECT BY PRIOR x=mgr
4 ORDER BY mgr
5 /
DATA X Y MGR LEVEL
---------- ---------- ---------- ---------- ----------
** 1 A 0 1
**** 2 B 1 2
**** 3 C 1 2
****** 4 D 2 3
****** 6 F 2 3
****** 5 E 3 3
******** 7 G 4 4
******** 8 H 6 4
8 rows selected.
one level=1 (start with)
connected to the two records such that their MGR = level 1's X=1 value.
If you leave off the start with, that is like saying "start with 1=1, EVERY record". So every record is a level one record (and maybe someone elses level 2, 3, 4, whatever....)
ops$tkyte%ORA11GR1> SELECT rpad('*',2*level,'*') data, x,y,mgr,LEVEL
2 FROM (SELECT x,y,mgr FROM counter )
3 START WITH 1=1 CONNECT BY PRIOR x=mgr
4 ORDER BY mgr
5 /
DATA X Y MGR LEVEL
---------- ---------- ---------- ---------- ----------
** 1 A 0 1
**** 2 B 1 2
**** 3 C 1 2
** 2 B 1 1
** 3 C 1 1
**** 4 D 2 2
****** 6 F 2 3
** 6 F 2 1
**** 6 F 2 2
** 4 D 2 1
****** 4 D 2 3
****** 5 E 3 3
**** 5 E 3 2
** 5 E 3 1
******** 7 G 4 4
****** 7 G 4 3
** 7 G 4 1
**** 7 G 4 2
**** 8 H 6 2
** 8 H 6 1
******** 8 H 6 4
****** 8 H 6 3
22 rows selected.
Good explanation
A reader, March 31, 2008 - 12:48 am UTC
March 31, 2008 - 9:27 am UTC
Howard Rogers decided to bag the site, it is gone.
Superb Explanation!!!
Bhushan, March 31, 2008 - 10:26 pm UTC
Can it get better guys!!!
Cheers to you Tom.
--Bhushan
Need help on avoiding FTS for using connect by prior
lava, April 07, 2008 - 4:17 pm UTC
Hi Tom,
Need some help on avoiding a FULL table scan on a connect by prior in a select statement. Is it possible to decrease the cost using a FBI or rewriting the sql to get the same resultset.
thanks for any feedback
lava
Added indexes on empno and mgr for doing index range scan.
create index idx1 on emp (empno);
create index idx2 on emp (mgr);
select empno
from emp
start with empno = 7698
connect by prior empno = mgr;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 CONNECT BY (WITH FILTERING)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
3 2 INDEX (RANGE SCAN) OF 'IDX1' (NON-UNIQUE)
4 1 NESTED LOOPS
5 4 BUFFER (SORT)
6 5 CONNECT BY PUMP
7 4 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
8 7 INDEX (RANGE SCAN) OF 'IDX2' (NON-UNIQUE)
9 1 TABLE ACCESS (FULL) OF 'EMP'
April 09, 2008 - 9:25 am UTC
ahh, the irrational fear of a full scan. It is so scary that even when it doesn't happen - people are fearful of it.
tkprof that
select empno
from emp
start with empno = 7698
connect by prior empno = mgr
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.03 0 3 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.00 0 5 0 6
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.01 0.03 0 8 0 6
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 96
Rows Row Source Operation
------- ---------------------------------------------------
6 CONNECT BY WITH FILTERING (cr=5 pr=0 pw=0 time=563 us)
1 TABLE ACCESS BY INDEX ROWID EMP (cr=2 pr=0 pw=0 time=103 us)
1 INDEX RANGE SCAN IDX1 (cr=1 pr=0 pw=0 time=66 us)(object id 56677)
5 NESTED LOOPS (cr=3 pr=0 pw=0 time=320 us)
6 BUFFER SORT (cr=0 pr=0 pw=0 time=122 us)
6 CONNECT BY PUMP (cr=0 pr=0 pw=0 time=60 us)
5 TABLE ACCESS BY INDEX ROWID EMP (cr=3 pr=0 pw=0 time=160 us)
5 INDEX RANGE SCAN IDX2 (cr=2 pr=0 pw=0 time=101 us)(object id 56678)
0 TABLE ACCESS FULL EMP (cr=0 pr=0 pw=0 time=0 us)
see how it does NO WORK, nothing. It never happened....
don't tune a plan, tune a question.
Not fearing the full tablescan after reading your books and your examples
A reader, April 10, 2008 - 3:31 pm UTC
Was assisting on performance tuning on a database.
They use a similar query for online/dss application. The app team uses a similar query on a table with 50K rows in test and 77k rows in prod. Based on the predicate used, it takes 2+seconds. Based on the complex sql statement, being used it takes 2 to several minutes to bring up their webpage. The expected response time for their reports and webpages is sub-second < 2 seconds.
Below is some of the information related to this.
Thanks for your earlier response.
lava
SQL> select count(*) from org_point;
COUNT(*)
----------
54462
SQL> set timing on
SQL> set autotrace traceonly explain statistics
SQL> SELECT DISTINCT ORG_POINT_ID
2 FROM ORG_POINT
3 START WITH ORG_POINT_ID = 350
4 CONNECT BY PRIOR ORG_POINT_ID = RPTS_TO_ORG_POINT_ID
5 ;
11777 rows selected.
Elapsed: 00:00:04.99
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=13 Card=83 Bytes=830)
1 0 SORT (UNIQUE) (Cost=13 Card=83 Bytes=830)
2 1 CONNECT BY (WITH FILTERING)
3 2 TABLE ACCESS (BY INDEX ROWID) OF 'ORG_POINT'
4 3 INDEX (UNIQUE SCAN) OF 'ORG_POINT_PK' (UNIQUE) (Cost=2 Card=1 Bytes=5)
5 2 NESTED LOOPS
6 5 BUFFER (SORT)
7 6 CONNECT BY PUMP
8 5 TABLE ACCESS (BY INDEX ROWID) OF 'ORG_POINT' (Cost=12 Card=83 Bytes=830)
9 8 INDEX (RANGE SCAN) OF 'ORG_POINT_I01' (NON-UNIQUE) (Cost=2 Card=75)
10 2 TABLE ACCESS (FULL) OF 'ORG_POINT'
Statistics
----------------------------------------------------------
14 recursive calls
72602 db block gets
1243 consistent gets
1908 physical reads
0 redo size
94948 bytes sent via SQL*Net to client
5738 bytes received via SQL*Net from client
787 SQL*Net roundtrips to/from client
8 sorts (memory)
2 sorts (disk)
11777 rows processed
April 10, 2008 - 3:43 pm UTC
tkprof please.
Tkprof report on the same sql statement.
lava, April 10, 2008 - 3:44 pm UTC
Tom,
Below is the tkprof report. Sorry for not giving the right information in the original posting.
lava
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.01 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 787 2.05 2.85 1776 1239 72602 11777
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 789 2.05 2.86 1776 1239 72602 11777
Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 592 (LAVATEST)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
11777 SORT (UNIQUE)
11777 CONNECT BY (WITH FILTERING)
2 TABLE ACCESS GOAL: ANALYZED (BY INDEX ROWID) OF 'ORG_POINT'
2 INDEX GOAL: ANALYZED (UNIQUE SCAN) OF 'ORG_POINT_PK' (UNIQUE)
5598 NESTED LOOPS
10 BUFFER (SORT)
10 CONNECT BY PUMP
5598 TABLE ACCESS GOAL: ANALYZED (BY INDEX ROWID) OF 'ORG_POINT'
5598 INDEX GOAL: ANALYZED (RANGE SCAN) OF 'ORG_POINT_I01' (NON-UNIQUE)
54462 TABLE ACCESS GOAL: ANALYZED (FULL) OF 'ORG_POINT'
April 10, 2008 - 3:52 pm UTC
create table and create index statements ...
but in general, looks OK so far - you get a ton of initial rows to start with, so using an index might well not make any sense at all.
2 sorts (disk)
you might have insufficient PGA allocated - the amount of data isn't that large.
you should trace with wait events so as to see what you are waiting on mostly.
Duplicated Children
Michael, April 23, 2008 - 9:23 am UTC
We are trying to create a table of historical org charts. As long as I only have one organization in the table, the quaery returns correctly, but as soon as I add another organization, the children are duplicated. What am I doing wrong? I have tried changing the where to be part of the connect by to no avail.
here is my script:
set scan off
--
drop table org_chart;
create table org_chart
(quarter number(1),
year number(4),
main_id number(9),
seq number(3),
parent number(3),
id number(9));
--
insert into org_chart values( 1, 2008, 480228, 1, null, 3510);
insert into org_chart values( 1, 2008, 480228, 82, 1, 1099579);
insert into org_chart values( 1, 2008, 480228, 89, 1, 1426755);
insert into org_chart values( 1, 2008, 480228, 100, 1, 27666);
insert into org_chart values( 1, 2008, 480228, 102, 100, 27183);
insert into org_chart values( 1, 2008, 480228, 109, 1, 38172);
--
commit;
--
column seq_num format a30
select lpad(' ', 4*(level-1))||seq as seq_num,
level, parent, id
from org_chart
where main_id = 480228 and quarter = 1 and year = 2008
start with seq = 1
connect by parent = prior seq;
--
insert into org_chart values( 1, 2008, 1022269, 1, null, 1022269);
insert into org_chart values( 1, 2008, 1022269, 2, 1, 1022278);
insert into org_chart values( 1, 2008, 1022269, 3, 2, 23502);
commit;
--
select lpad(' ', 4*(level-1))||seq as seq_num,
level, parent, id
from org_chart
where main_id = 480228 and quarter = 1 and year = 2008
start with seq = 1
connect by parent = prior seq;
--
here is the output from the first select:
SEQ_NUM LEVEL PARENT ID
------------------------------ ---------- ---------- ----------
1 1 3510
82 2 1 1099579
89 2 1 1426755
100 2 1 27666
102 3 100 27183
109 2 1 38172
Here is the second select result:
SEQ_NUM LEVEL PARENT ID
------------------------------ ---------- ---------- ----------
1 1 3510
82 2 1 1099579
89 2 1 1426755
100 2 1 27666
102 3 100 27183
109 2 1 38172
82 2 1 1099579
89 2 1 1426755
100 2 1 27666
102 3 100 27183
109 2 1 38172
11 rows selected.
April 28, 2008 - 9:23 am UTC
given that only you understand your data model, only you can answer your question.
I mean, come on... a little explanation of how you are storing your data would be called for.
no clue what the meaning of "main_id" is - but it must be important, since you "where" on it.
and you do know that:
where main_id = 480228 and quarter = 1 and year = 2008
start with seq = 1
connect by parent = prior seq;
means
a) find all rows with seq=1
b) build the entire hierarchy by connecting parent to prior seq
c) THEN keep only rows where main_id = 480228, quarter=1 and year = 2008.
and you do know that storing things as "year" and "quarter" is not a good thing, you should have a single attribute "the_quarter" that has a DATE in it.
More info
Michael, May 01, 2008 - 10:26 am UTC
I thought I had given enough info, but I guess not! This table is to hold thousands of companies, for multiple time periods. The main_id is the id of the top-level parent, id is the individual company id. So main_id 480228 is one company with his siblings. main_id 1022269 is another company. The query works correctly when there is just one company in the table, but, when I add a second company, the results duplicate. When I try moving the where to the connect, I get the same result: duplicated. Based upon what you wrote, I would expect the following to work correctly, and return the same as the first query (with one company in the table):
select lpad(' ', 4*(level-1))||seq as seq_num,
level, parent, id
from org_chart
start with seq = 1
connect by parent = prior seq
and main_id = 480228 and quarter = 1 and year = 2008;
But this returns the same as using the where. Based upon what I have seen, it looks like one can not use this query if the table contains multiple company hierarchies (multiple families). I know my data, and have put together a very simple example for this. I know what I expect to get, but don't understand why I am getting duplicated results. thanks
May 01, 2008 - 11:49 am UTC
... When I try moving the where to the connect, I
get the same result: duplicated....
you keep saying duplicated - but you see, your queries return exactly what you code them to return - instead of showing us queries that do not work - be explicit, tell us what you mean - maybe by showing us your EXPECTED output with lots of detail as to why this is what you expect.
why would you connect by a constant main_id like that?
Mohammed Khaliq, May 12, 2008 - 1:49 am UTC
Hi:
I have hierarchical query where i would like to know all childs of the parent and thier levels(considering 'n' levels of generation)
May 12, 2008 - 1:30 pm UTC
well, if you have a hierarchical query, you already have that - don't you.
I mean, that is what the query returns.
Mohammed Khaliq, May 12, 2008 - 1:49 am UTC
Hi:
I have hierarchical query where i would like to know all childs of the parent and thier levels(considering 'n' levels of generation)
Stored procedure
Mohammed Khaliq, May 12, 2008 - 2:06 am UTC
Hi:
I have hierarchical query where i would like to know all childs of a parent if parent_id is given as input(considering 'n' levels of generation) in oracle
CREATE TABLE AD_PPARENT (
ID NUMBER (10) NOT NULL,
NAME VARCHAR2 (30),
PAID NUMBER (10),
PANAME VARCHAR2 (30),
GENDER CHAR (1),
PRIMARY KEY ( ID ));
CREATE OR REPLACE PROCEDURE SP_GETCHILD (PARENT_ID IN NUMBER)
AS
V_ID NUMBER(10,0);
V_GENDER CHAR(1);
V_NAME VARCHAR2(30);
CURSOR getchild IS SELECT id, name, gender FROM AD_PPARENT where PAID = PARENT_ID;
BEGIN
open getchild;
fetch getchild into V_ID,V_NAME , V_GENDER;
while(getchild%FOUND) loop
dbms_output.put_line (' CHILD ID == ' || V_ID || ' ' || 'CHILD NAME == ' || V_NAME || ' ' || 'CHILD GENDER == ' || V_GENDER );
fetch getchild into V_ID,V_NAME, V_GENDER;
end loop;
END;
/
May 12, 2008 - 1:34 pm UTC
sorry, this does not make sense, you just answered your own question here? Or are you saying "I don't know how to write a connect by, I don't actually have the query yet"
by the way,you should just code:
CREATE OR REPLACE PROCEDURE SP_GETCHILD (p_PARENT_ID IN NUMBER)
AS
CURSOR getchild IS <b>
SELECT level id, name, gender
FROM AD_PPARENT
start with PAID = PARENT_ID
connect by prior id = parent_id;</b>
BEGIN
for x in (getchild)
loop
dbms_output.put_line
(' CHILD ID == ' || x.ID || ' ' || 'CHILD NAME == ' ||
x.NAME || ' ' || 'CHILD GENDER == ' || x.GENDER );
end loop;
END;
/
I see you are a sqlserver developer - take a bit of time to learn plsql and you'll find it to be a little better than the rather rudimentary t-sql you've left behind.
Stored Procedure
Mohammed Khaliq, May 13, 2008 - 1:38 am UTC
hi Tom,
I have created the below store proc but it does not give me the required output.
I got the following feedback from my manager"Where are you getting the value of v_level_id in 'CURSOR getchild IS SELECT ID,NAME,LEVEL_ID FROM PARENT where PARENT_ID = P_PARENT_ID AND LEVEL_ID=V_LEVEL_ID;'.
i believe the initial value of v_level_id is zero and the above query would return you all rows corresponding to the given parentid with level=0 which does not solve the problem."
Please help me with the required changes to be made in the store proc for getting the right output.
CREATE TABLE PARENT (
NAME VARCHAR2 (30),
PARENT_ID NUMBER (10),
LEVEL_ID NUMBER (10),
ID NUMBER (10) NOT NULL,
CONSTRAINT PRIMARYKEY
PRIMARY KEY ( ID );
CREATE OR REPLACE PROCEDURE SP_GETCHILD (P_PARENT_ID IN NUMBER)
AS
V_ID NUMBER(10,0);
V_LEVEL_ID NUMBER(10,0);
V_NAME VARCHAR2(30);
CURSOR getchild IS SELECT ID,NAME,LEVEL_ID FROM PARENT where PARENT_ID = P_PARENT_ID AND LEVEL_ID=V_LEVEL_ID;
BEGIN
SELECT LEVEL_ID INTO V_LEVEL_ID FROM PARENT WHERE ID = P_PARENT_ID;
V_LEVEL_ID := V_LEVEL_ID + 1;
open getchild;
fetch getchild into V_ID,V_NAME ,V_LEVEL_ID;
while(getchild%FOUND) loop
dbms_output.put_line (' CHILD ID == ' || V_ID || ' ' || 'CHILD NAME == ' || V_NAME || ' ' || 'LEVEL_ID == ' || V_LEVEL_ID );
fetch getchild into V_ID,V_NAME, V_LEVEL_ID;
end loop;
END;
/
regards
khaliq
May 13, 2008 - 10:31 am UTC
... I have created the below store proc but it does not give me the required
output ...
one would need requirements then, would not one?
I have no idea what you are really looking for.
stop using the open/fetch stuff - you'll introduce more bugs than not - AND your code will just run slower. Take what I gave you and start from there (lots of stuff to UNLEARN from sqlserver - tons of bad habits!!)
You ignored my code above entirely, I have no idea what you are really looking for, you need to be a bit more precise specification wise.
Removing Duplicates for Multiple Parents in a Hierarchical Query
Edward Girard, July 25, 2008 - 1:48 pm UTC
A note can be stored at any node of the CUSTOMER hierarchy below. I'm writing a query to retrieve all notes in the hierarchy for a specific customer. The query below returns all notes starting at a specific node (ie. CUSTOMER) on down the hierarchy.
Two questions:
1) How can I restrict the query to retrieve notes down to a certain level (say, all notes from CONTRACT to INVOICE_LINE_ITEM?
2) How can I remove the duplicate note (specifically the 2nd occurence) that will always appear at a node that has 2 parents (see: INVOICE_LINE and CREDIT_APPLICATION) and still keep the query sorted by Parent_ID and Note_ID? I've tried using DISTINCT but get the error "Not a SELECTed expression". I've also tried inlines views and correlated subquerys to no avail. I'm obviously missing something easy.
Note 1: If you start with CONTRACT, CREDIT_APPLICATION appears twice as well but shouldn't because one of its parents - CREDIT - is not included in the hierarchy.
Note 2: Having the Parent_ID column in the query is not necessary (just TABLE_NAME, DISPLAY, and NOTE in the correct order).
Thanks
Customer Hierarchy
==================
CUSTOMER (top)
|
^
CUSTOMER_ACCOUNT <------------- CREDIT
| |
^ ^
CONTRACT <-------- INVOICE <---- CREDIT_APPLICATION
| |
^ ^
CONTRACT_LINE <--- INVOICE_LINE
|
^
INVOICE_LINE_ITEM
|
^
INVOICE_LINE_ITEM_CHG
|
^
INVOICE_LINE_ITEM_CHG_TAX (bottom)
set linesize 140
column table_name format a25
column display_name format a30
column note format a65
SELECT srt.parent_ID,
srt.table_name AS TABLE_NAME,
srt.display_name AS Display,
-- nrt.ref_uid_value AS REF_ID,
-- n.id,
n.note
FROM note n,
note_ref_table nrt,
sys_ref_table srt,
(SELECT DISTINCT sr1.id,
sr1.table_name
FROM sys_ref_table sr1
START WITH sr1.id = (SELECT sr2.id
FROM sys_ref_table sr2
WHERE sr2.table_name = 'CUSTOMER')
CONNECT BY PRIOR sr1.id = sr1.parent_id
ORDER BY sr1.id) ord
WHERE n.id = nrt.note_id
AND nrt.ref_table_id IN ord.id
AND srt.table_name = ord.table_name
ORDER BY srt.parent_ID,
n.id;
PARENT_ID TABLE_NAME DISPLAY NOTE
---------- ------------------------- ------------------------------ ---------------------------------------------------------------
0 CUSTOMER Customer CUSTOMER Note #1 for Invoice#: 000000000004273
1 CUSTOMER_ACCOUNT Customer Account CUSTOMER_ACCOUNT Note #1 for Invoice#: 000000000004273
2 CONTRACT Contract CONTRACT Note #1 for Invoice#: 000000000004273
2 CREDIT Credit CREDIT Note #1 for Invoice#: 000000000004273
3 INVOICE Invoice INVOICE Note #1 for Invoice#: 000000000004273
3 CONTRACT_LINE Contract Line CONTRACT_LINE Note #1 for Invoice#: 000000000004273
4 INVOICE_LINE Invoice Line INVOICE_LINE Note #1 for Invoice#: 000000000004273
5 INVOICE_LINE Invoice Line INVOICE_LINE Note #1 for Invoice#: 000000000004273
5 CREDIT_APPLICATION Credit Application CREDIT_APPLICATION Note #1 for Invoice#: 000000000004273
6 INVOICE_LINE_ITEM Invoice Line Item INVOICE_LINE_ITEM Note #1 for Invoice#: 000000000004273
6 INVOICE_LINE_ITEM Invoice Line Item INVOICE_LINE_ITEM Note #2 for Invoice#: 000000000004273
6 INVOICE_LINE_ITEM Invoice Line Item INVOICE_LINE_ITEM Note #3 for Invoice#: 000000000004273
8 INV_LINE_ITEM_CHG Invoice Line Item Charge INVOICE_LINE_ITEM_CHG Note #1 for Invoice#: 000000000004273
8 INV_LINE_ITEM_CHG Invoice Line Item Charge INVOICE_LINE_ITEM_CHG Note #2 for Invoice#: 000000000004273
8 INV_LINE_ITEM_CHG Invoice Line Item Charge INVOICE_LINE_ITEM_CHG Note #3 for Invoice#: 000000000004271
8 INV_LINE_ITEM_CHG Invoice Line Item Charge INVOICE_LINE_ITEM_CHG Note #4 for Invoice#: 000000000004273
8 INV_LINE_ITEM_CHG Invoice Line Item Charge INVOICE_LINE_ITEM_CHG Note #5 for Invoice#: 000000000004273
9 INV_LINE_ITEM_CHG_TAX Invoice Line Item Charge Tax INVOICE_LINE_ITEM_CHG_TAX Note #1 for Invoice#: 000000000004273
9 INV_LINE_ITEM_CHG_TAX Invoice Line Item Charge Tax INVOICE_LINE_ITEM_CHG_TAX Note #2 for Invoice#: 000000000004273
9 INV_LINE_ITEM_CHG_TAX Invoice Line Item Charge Tax INVOICE_LINE_ITEM_CHG_TAX Note #3 for Invoice#: 000000000004273
11 CREDIT_APPLICATION Credit Application CREDIT_APPLICATION Note #1 for Invoice#: 000000000004273
/* CREATE TABLES */
CREATE TABLE SYS_REF_TABLE
(
ID NUMBER,
PARENT_ID NUMBER,
TABLE_NAME VARCHAR2(30),
DISPLAY_NAME VARCHAR2(100)
);
CREATE UNIQUE INDEX SYS_REF_TABLE_PK ON SYS_REF_TABLE
(ID, PARENT_ID);
CREATE TABLE NOTE
(
ID NUMBER NOT NULL,
NOTE VARCHAR2(4000) NOT NULL
);
CREATE UNIQUE INDEX NOTE_PK ON NOTE
(ID);
CREATE TABLE NOTE_REF_TABLE
(
NOTE_ID NUMBER NOT NULL,
REF_TABLE_ID NUMBER NOT NULL,
REF_UID_VALUE NUMBER NOT NULL
);
CREATE UNIQUE INDEX NOTE_REF_TABLE_PK ON NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE);
/* SYS_REF_TABLE */
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(1, 'CUSTOMER', 'Customer', 0);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(2, 'CUSTOMER_ACCOUNT', 'Customer Account', 1);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(7, 'ISSUE', 'Issue', 2);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(3, 'CONTRACT', 'Contract', 2);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(11, 'CREDIT', 'Credit', 2);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(4, 'CONTRACT_LINE', 'Contract Line', 3);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(5, 'INVOICE', 'Invoice', 3);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(6, 'INVOICE_LINE', 'Invoice Line', 4);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(6, 'INVOICE_LINE', 'Invoice Line', 5);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(12, 'CREDIT_APPLICATION', 'Credit Application', 5);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(8, 'INVOICE_LINE_ITEM', 'Invoice Line Item', 6);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(9, 'INV_LINE_ITEM_CHG', 'Invoice Line Item Charge', 8);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(10, 'INV_LINE_ITEM_CHG_TAX', 'Invoice Line Item Charge Tax', 9);
Insert into SYS_REF_TABLE
(ID, TABLE_NAME, DISPLAY_NAME, PARENT_ID)
Values
(12, 'CREDIT_APPLICATION', 'Credit Application', 11);
/* NOTE */
Insert into NOTE
(ID, NOTE)
Values
(10187, 'INVOICE Note #1 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10274, 'CREDIT Note #1 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10273, 'CUSTOMER Note #1 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10272, 'CONTRACT_LINE Note #1 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10271, 'CONTRACT Note #1 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10270, 'CUSTOMER_ACCOUNT Note #1 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10269, 'INVOICE_LINE_ITEM_CHG_TAX Note #3 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10268, 'INVOICE_LINE_ITEM_CHG_TAX Note #2 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10267, 'INVOICE_LINE_ITEM_CHG_TAX Note #1 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10266, 'INVOICE_LINE_ITEM_CHG Note #5 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10265, 'INVOICE_LINE_ITEM_CHG Note #4 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10264, 'INVOICE_LINE_ITEM_CHG Note #3 for Invoice#: 000000000004271');
Insert into NOTE
(ID, NOTE)
Values
(10263, 'INVOICE_LINE_ITEM_CHG Note #2 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10262, 'INVOICE_LINE_ITEM_CHG Note #1 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10260, 'INVOICE_LINE_ITEM Note #3 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10259, 'INVOICE_LINE_ITEM Note #2 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10258, 'INVOICE_LINE_ITEM Note #1 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10257, 'INVOICE_LINE Note #1 for Invoice#: 000000000004273');
Insert into NOTE
(ID, NOTE)
Values
(10280, 'CREDIT_APPLICATION Note #1 for Invoice#: 000000000004273');
/* NOTE_REF_TABLE */
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10274, 11, 191);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10273, 1, 285);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10272, 4, 52);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10271, 3, 310);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10270, 2, 53);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10269, 10, 84756);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10268, 10, 84765);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10267, 10, 84761);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10266, 9, 44512);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10265, 9, 44511);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10264, 9, 44510);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10263, 9, 44507);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10262, 9, 44505);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10260, 8, 24784);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10259, 8, 24782);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10258, 8, 24781);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10187, 5, 4273);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10257, 6, 4271);
Insert into NOTE_REF_TABLE
(NOTE_ID, REF_TABLE_ID, REF_UID_VALUE)
Values
(10280, 12, 256);
commit;
Performance of hierarchical query
Dibyendu, August 28, 2008 - 2:28 am UTC
I have a procedure which has number of select statements.
I tried to execute the queries separately.
One of those queries is:
SELECT COUNT(C.CASE_ID) p_count_new_cases
FROM T_CASES C, T_NOTES N, T_USERS TU
WHERE C.CASE_ID = N.CASE_ID
AND C.CASE_OWNER_USER_ID=TU.USER_ID
AND C.STATUS = 'OPEN'
AND N.CREATED_BY != C.CASE_OWNER_USER_ID
AND N.MOD_BY != C.CASE_OWNER_USER_ID
START WITH TU.USER_ID=p_emp_id CONNECT BY PRIOR TU.USER_ID=TU.REPORTS_TO;
The tables t_cases has around 1591256 rows, t_notes table has 12257426 rows and t_users has 3155.
user_id column is primary key in t_users table.
When I executed the query only for the condition TU.user_id=p_emp_id, the query gets executed taking small amount of time.
When we add the hierarchical part (START WITH TU.USER_ID=p_emp_id CONNECT BY PRIOR TU.USER_ID=TU.REPORTS_TO), the query takes a long time to execute(more than 45 minutes).
I created indexes on case_owner_user_id and status column. But the execution time is not reduced.
I am giving the execution plan for the query.
SQL> set autotrace traceonly explain;
SQL> SELECT COUNT(C.CASE_ID) p_count_new_cases
2 FROM T_CASES C, T_NOTES N, T_USERS TU
3 WHERE C.CASE_ID = N.CASE_ID
4 AND C.CASE_OWNER_USER_ID=TU.USER_ID
5 AND C.STATUS = 'OPEN'
6 AND N.CREATED_BY != C.CASE_OWNER_USER_ID
7 AND N.MOD_BY != C.CASE_OWNER_USER_ID
8 START WITH TU.USER_ID='X656629' CONNECT BY PRIOR TU.USER_ID=TU.REPORTS_TO;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=111475 Card=1 Byte
s=56)
1 0 SORT (AGGREGATE)
2 1 FILTER
3 2 CONNECT BY (WITH FILTERING)
4 3 FILTER
5 4 COUNT
6 5 NESTED LOOPS (Cost=111475 Card=12175742 Bytes=68
1841552)
7 6 NESTED LOOPS (Cost=90 Card=1591221 Bytes=57283
956)
8 7 TABLE ACCESS (FULL) OF 'T_USERS' (TABLE) (Co
st=26 Card=3153 Bytes=47295)
9 7 TABLE ACCESS (BY INDEX ROWID) OF 'T_CASES' (
TABLE) (Cost=1 Card=505 Bytes=10605)
10 9 INDEX (RANGE SCAN) OF 'IDX_CASE_OWNER_USER
_ID' (INDEX) (Cost=1 Card=2364)
11 6 TABLE ACCESS (BY INDEX ROWID) OF 'T_NOTES' (TA
BLE) (Cost=1 Card=8 Bytes=160)
12 11 INDEX (RANGE SCAN) OF 'NDXT_NOTES_CASE_ID' (
INDEX) (Cost=1 Card=58)
13 3 HASH JOIN
14 13 CONNECT BY PUMP
15 13 COUNT
16 15 NESTED LOOPS (Cost=111475 Card=12175742 Bytes=68
1841552)
17 16 NESTED LOOPS (Cost=90 Card=1591221 Bytes=57283
956)
18 17 TABLE ACCESS (FULL) OF 'T_USERS' (TABLE) (Co
st=26 Card=3153 Bytes=47295)
19 17 TABLE ACCESS (BY INDEX ROWID) OF 'T_CASES' (
TABLE) (Cost=1 Card=505 Bytes=10605)
20 19 INDEX (RANGE SCAN) OF 'IDX_CASE_OWNER_USER
_ID' (INDEX) (Cost=1 Card=2364)
21 16 TABLE ACCESS (BY INDEX ROWID) OF 'T_NOTES' (TA
BLE) (Cost=1 Card=8 Bytes=160)
22 21 INDEX (RANGE SCAN) OF 'NDXT_NOTES_CASE_ID' (
INDEX) (Cost=1 Card=58)
23 3 COUNT
24 23 NESTED LOOPS (Cost=111475 Card=12175742 Bytes=6818
41552)
25 24 NESTED LOOPS (Cost=90 Card=1591221 Bytes=5728395
6)
26 25 TABLE ACCESS (FULL) OF 'T_USERS' (TABLE) (Cost
=26 Card=3153 Bytes=47295)
27 25 TABLE ACCESS (BY INDEX ROWID) OF 'T_CASES' (TA
BLE) (Cost=1 Card=505 Bytes=10605)
28 27 INDEX (RANGE SCAN) OF 'IDX_CASE_OWNER_USER_I
D' (INDEX) (Cost=1 Card=2364)
29 24 TABLE ACCESS (BY INDEX ROWID) OF 'T_NOTES' (TABL
E) (Cost=1 Card=8 Bytes=160)
30 29 INDEX (RANGE SCAN) OF 'NDXT_NOTES_CASE_ID' (IN
DEX) (Cost=1 Card=58)
I could not give you tkprof report as I dont have access to that.
Could you please tell me how to tune these queries?
I am using oracle 10.2.0.3.0 in windows.
August 29, 2008 - 3:28 pm UTC
ugh, that is an ugly one:
SQL> SELECT COUNT(C.CASE_ID) p_count_new_cases
2 FROM T_CASES C, T_NOTES N, T_USERS TU
3 WHERE C.CASE_ID = N.CASE_ID
4 AND C.CASE_OWNER_USER_ID=TU.USER_ID
5 AND C.STATUS = 'OPEN'
6 AND N.CREATED_BY != C.CASE_OWNER_USER_ID
7 AND N.MOD_BY != C.CASE_OWNER_USER_ID
8 START WITH TU.USER_ID='X656629' CONNECT BY PRIOR TU.USER_ID=TU.REPORTS_TO;
non-equi joins.
looking at the card= values, it thinks it is basically going to get "a ton of rows" - but I cannot tell - you have a simple "count" (without a tkprof, this is difficult to look at).
how big would:
SQL> SELECT *
2 FROM T_USERS TU
8 START WITH TU.USER_ID='X656629' CONNECT BY PRIOR TU.USER_ID=TU.REPORTS_TO;
by itself be? (how big is the hierarchy)
How big would:
SQL> SELECT *
2 FROM T_CASES C, T_USERS TU
4 AND C.CASE_OWNER_USER_ID=TU.USER_ID
5 AND C.STATUS = 'OPEN' and TU.USER_ID='X656629'
be as opposed to just select * from t_users tu where TU.USER_ID='X656629'
that is - should we
a) build heirarchy, and then join
b) join and then build hierarchy
in order to try and determine that, we'd need to know what some of those subresults would look like.
hierachy with many-to-many
A reader, September 08, 2008 - 5:37 pm UTC
Hi Tom,
I have three tables A<-- b -->C where b is mapping table.
I need to write hierarchical query that would return all rows from "A" where "A.id" has a match in "b.a_id".
Could you please show some primitive example using this condition if it's even possible?
Sorry for formatting couldn't get rid of this new line character in my text.
Thank you in advance.
September 09, 2008 - 7:25 am UTC
I see nothing here to support a hierarchy.
I see a join perhaps, but that is trivial. I don't see any "parent child" columns to have a hierarchy appear from
qustion about nocycle
James Su, September 12, 2008 - 10:45 pm UTC
hi Tom,
CREATE TABLE my_table (node VARCHAR2(1), linked_to VARCHAR2(1));
INSERT INTO my_table VALUES ('A','B');
INSERT INTO my_table VALUES ('B','A');
INSERT INTO my_table VALUES ('B','C');
INSERT INTO my_table VALUES ('C','B');
SELECT level,node,linked_to,SYS_CONNECT_BY_PATH(node,'/')||'/'||linked_to as PATH
FROM my_table
START WITH node = 'A'
CONNECT BY NOCYCLE node = PRIOR linked_to;
LEVEL N L PATH
--------- - - --------------------------------
1 A B /A/B
2 B A /A/B/A
2 B C /A/B/C
My question is: why my last inserted row (from C to B) is not selected? If this is how NOCYCLE works, why the second inserted row is selected?
You can see path like: /A/B/A
Node B is also linked back from C, why don't we see: /A/B/C/B ?
Thank you.
question about NOCYCLE
James Su, September 17, 2008 - 11:59 am UTC
Dear Tom, I know you are very busy, but could you please take a look at the question above? Thank you!
September 17, 2008 - 12:17 pm UTC
the immediate child of a root is treated differently than one further down.
start with A.
a connects to b
b connects to A and C
we can now detect there is a cycle from b to a.
and looking forward, we can detect there is a cycle from b to c as well.
if you insert another row:
ops$tkyte%ORA11GR1> insert into my_table values ( 'x', 'A' );
ops$tkyte%ORA11GR1> SELECT level,node,linked_to,SYS_CONNECT_BY_PATH(node,'/')||'/'||linked_to as PATH
2 FROM my_table
3 START WITH node = 'x'
4 CONNECT BY NOCYCLE node = PRIOR linked_to;
LEVEL N L PATH
---------- - - ----------------------------------------
1 x A /x/A
2 A B /x/A/B
3 B C /x/A/B/C
that is almost like starting with A, since x -> A
x connects to A
A connects to B
B connects to C
but note that B connecting to A isn't there this time, it wasn't an immediate child of the root.
how to calculate accumulative balance
abu abdullah, October 25, 2008 - 9:33 am UTC
hi Tom,
I have chart_of_account table, with items
(account_no,
account_name,
account_parent,
account_level, -- 1= main, 2= leave
balance)
balance is only real for leaves, but for main levels is accumulative,
So, when I make a tree, as follow:
account_no account_parent account_level balance
---------- -------------- ------------ -------
1000 null 1
1100 1000 1
1110 1100 1
1111 1110 2 50
1200 1000 1
1210 1200 1
1211 1210 2 70
1300 1000 1
1310 1300 1
1311 1310 2 90
I want the output to be as follow:
account_no account_parent account_level balance
---------- -------------- ------------ -------
1000 null 1 210
1100 1000 1 50
1110 1100 1 50
1111 1110 2 50
1200 1000 1 70
1210 1200 1 70
1211 1210 2 70
1300 1000 1 90
1310 1300 1 90
1311 1310 2 90
thank you.
October 25, 2008 - 6:42 pm UTC
no create
no inserts
no look
how can I do the balance of accounts ?
abu mahmoud, October 26, 2008 - 9:34 am UTC
ok. Mr. Tom,
I have a table as follow:
SQL> create table chart_of_accounts
2 (account_no number(4),
3 account_name varchar2(50),
4 account_parent number(4),
5 account_level number(1), -- 1= main, 2= leave
6 balance number(10,2)
7 )
8 ;
Table created.
SQL> insert into chart_of_accounts values(1000, 'Assets', null, 1, null);
1 row created.
SQL> insert into chart_of_accounts values(1100, 'Fixed Assets', 1000, 1, null);
1 row created.
SQL> insert into chart_of_accounts values(1110, 'Furniture', 1100, 1, null);
1 row created.
SQL> insert into chart_of_accounts values(1111, 'Office Table', 1110, 2, 50);
1 row created.
SQL> insert into chart_of_accounts values(1200, 'Current Assets', 1000, 1, null);
1 row created.
SQL> insert into chart_of_accounts values(1210, 'Banks', 1200, 1, null);
1 row created.
SQL> insert into chart_of_accounts values(1211, 'Housing Bank', 1210, 2, 2560.73);
1 row created.
SQL> insert into chart_of_accounts values(1300, 'Cooperatives', 1000, 1, null);
1 row created.
SQL> insert into chart_of_accounts values(1310, 'Mobile Cooperatives', 1300, 1, null);
1 row created.
SQL> insert into chart_of_accounts values(1311, 'N95', 1310, 2, 600.00 );
1 row created.
SQL>
balance is only real for leaves, but for main levels is accumulative,
So, when I make a tree, as follow:
SQL> select * from chart_of_accounts ;
ACCOUNT_NO ACCOUNT_NAME ACCOUNT_PARENT ACCOUNT_LEVEL BALANCE
---------- -------------------------------------------------- -------------- ------------- ---------
1000 Assets 1
1100 Fixed Assets 1000 1
1110 Furniture 1100 1
1111 Office Table 1110 2 50
1200 Current Assets 1000 1
1210 Banks 1200 1
1211 Housing Bank 1210 2 2560.73
1300 Cooperatives 1000 1
1310 Mobile Cooperatives 1300 1
1311 N95 1310 2 600
10 rows selected.
SQL>
I want the output to be as follow:
ACCOUNT_NO ACCOUNT_NAME ACCOUNT_PARENT ACCOUNT_LEVEL BALANCE
---------- -------------------------------------------------- -------------- ------------- ---------
1000 Assets 1 3210.73
1100 Fixed Assets 1000 1 50
1110 Furniture 1100 1 50
1111 Office Table 1110 2 50
1200 Current Assets 1000 1 2560.73
1210 Banks 1200 1 2560.73
1211 Housing Bank 1210 2 2560.73
1300 Cooperatives 1000 1 600
1310 Mobile Cooperatives 1300 1 600
1311 N95 1310 2 600
thank you.
October 26, 2008 - 10:33 am UTC
ops$tkyte%ORA10GR2> select rpad('*',2*level,'*') || account_name nm, account_no, balance,
2 (select sum(balance) from chart_of_accounts c2 start with c2.rowid = c1.rowid connect by prior account_no = account_parent ) bal
3 from chart_of_accounts c1
4 start with account_parent is null
5 connect by prior account_no = account_parent
6 /
NM ACCOUNT_NO BALANCE BAL
---------------------------------------- ---------- ---------- ----------
**Assets 1000 3210.73
****Fixed Assets 1100 50
******Furniture 1110 50
********Office Table 1111 50 50
****Current Assets 1200 2560.73
******Banks 1210 2560.73
********Housing Bank 1211 2560.73 2560.73
****Cooperatives 1300 600
******Mobile Cooperatives 1310 600
********N95 1311 600 600
10 rows selected.
abu mahmoud, October 27, 2008 - 5:07 am UTC
Oh, Mr. Tom,
you are a great man.
thank you very much.
but, can you emplain me how you think with this problem.
i.e trace the sql statement.
so thanks.
October 27, 2008 - 8:07 am UTC
ops$tkyte%ORA10GR2> select rpad('*',2*level,'*') || account_name nm, account_no, balance,
2 <b> (select sum(balance) from chart_of_accounts c2 start with c2.rowid = c1.rowid connect by
prior account_no = account_parent ) bal </b>
3 from chart_of_accounts c1
4 start with account_parent is null
5 connect by prior account_no = account_parent
6 /
the bit in bold just sums up the balanced for the current record and all of it's children - that is all.
Can we get to the PArent Table
Bhushan, November 19, 2008 - 2:49 am UTC
Hi Tom,
I was trying to write a SQL which can give me the Main or the parent table.
If the input to the table is X has Foreign Key linked to Y and Y has a foreign key linked to Z then tha SQL should give me all the details
x(col1)->y(col1)
y(col1) -> z(col1)
The SQL might make clear what i am trying to achieve.
select DISTINCT a.table_name tab_name,c.column_name col_name ,c.table_name tab_name1,d.column_name col_name1
from
(select r_constraint_name,constraint_type,constraint_name,table_name from all_constraints) A,
(select r_constraint_name,constraint_type,constraint_name,table_name from all_constraints) b,
(select * from all_cons_columns) c,
(select * from all_cons_columns) d
where a.r_constraint_name=b.constraint_name and
a.constraint_type='R' and a.r_constraint_name=c.constraint_name
and a.constraint_name=d.constraint_name
START WITH a.table_name='X'
CONNECT BY PRIOR c.table_name=a.table_name
Your comments would be helpful and appreciated.
Thanks & Regards,
Bhushan Salgar
November 24, 2008 - 10:32 am UTC
but z could have a foreign key to x and the cycle begins.... cycles make this "hard"
ops$tkyte%ORA10GR2> create table p
2 ( a int, b int,
3 constraint p_pk primary key(a,b)
4 );
Table created.
ops$tkyte%ORA10GR2> create table c1
2 ( x int, y int, z int,
3 constraint c1_fk_p foreign key(x,y) references p(a,b),
4 constraint c1_pk primary key(x,y,z)
5 );
Table created.
ops$tkyte%ORA10GR2> create table c2
2 ( x int, y int, z int,
3 constraint c2_fk_c1 foreign key(x,y,z) references c1(x,y,z),
4 constraint c2_pk primary key(x,y,z)
5 );
Table created.
ops$tkyte%ORA10GR2> create table c3
2 ( x int, y int, z int,
3 constraint c3_fk_c2 foreign key(x,y,z) references c2(x,y,z),
4 constraint c3_pk primary key(x,y,z),
5 constraint c3_fk_p foreign key(x,y) references p(a,b),
6 constraint c3_unique unique (x,y)
7 );
Table created.
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> alter table p add
2 constraint p_fk_c3 foreign key(a,b) references c3(x,y);
Table altered.
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> variable bv varchar2(30)
ops$tkyte%ORA10GR2> exec :bv := 'P'
PL/SQL procedure successfully completed.
ops$tkyte%ORA10GR2> with data
2 as
3 (select a.table_name child, a.constraint_name child_cons,
4 b.table_name parent, b.constraint_name parent_cons
5 from user_constraints a, user_constraints b
6 where a.constraint_type = 'R'
7 and a.r_constraint_name = b.constraint_name
8 )
9 select rpad('*',2*level,'*') || child tree, data.* ,
10 (select rtrim(
11 max(decode(position,1,column_name||',')) ||
12 max(decode(position,2,column_name||',')) ||
13 max(decode(position,3,column_name||',')) ||
14 max(decode(position,4,column_name||',')) ||
15 max(decode(position,5,column_name)) ||
16 max(decode(position,6,'...')), ',' )
17 from user_cons_columns
18 where constraint_name = child_cons ) child_fkey,
19 (select rtrim(
20 max(decode(position,1,column_name||',')) ||
21 max(decode(position,2,column_name||',')) ||
22 max(decode(position,3,column_name||',')) ||
23 max(decode(position,4,column_name||',')) ||
24 max(decode(position,5,column_name)) ||
25 max(decode(position,6,'...')), ',' )
26 from user_cons_columns
27 where constraint_name = parent_cons ) parent_key
28 from data
29 start with child = :bv
30 connect by NOCYCLE prior parent = child
31 /
TREE PAR CHILD_CONS PARENT_CON CHILD PAREN
-------------------- --- ---------- ---------- ----- -----
**P C3 P_FK_C3 C3_UNIQUE A,B X,Y
****C3 P C3_FK_P P_PK X,Y A,B
****C3 C2 C3_FK_C2 C2_PK X,Y,Z X,Y,Z
******C2 C1 C2_FK_C1 C1_PK X,Y,Z X,Y,Z
********C1 P C1_FK_P P_PK X,Y A,B
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> exec :bv := 'C1'
PL/SQL procedure successfully completed.
ops$tkyte%ORA10GR2> /
TREE PAR CHILD_CONS PARENT_CON CHILD PAREN
-------------------- --- ---------- ---------- ----- -----
**C1 P C1_FK_P P_PK X,Y A,B
****P C3 P_FK_C3 C3_UNIQUE A,B X,Y
******C3 C2 C3_FK_C2 C2_PK X,Y,Z X,Y,Z
********C2 C1 C2_FK_C1 C1_PK X,Y,Z X,Y,Z
ops$tkyte%ORA10GR2> exec :bv := 'C2'
PL/SQL procedure successfully completed.
ops$tkyte%ORA10GR2> /
TREE PAR CHILD_CONS PARENT_CON CHILD PAREN
-------------------- --- ---------- ---------- ----- -----
**C2 C1 C2_FK_C1 C1_PK X,Y,Z X,Y,Z
****C1 P C1_FK_P P_PK X,Y A,B
******P C3 P_FK_C3 C3_UNIQUE A,B X,Y
********C3 C2 C3_FK_C2 C2_PK X,Y,Z X,Y,Z
ops$tkyte%ORA10GR2> exec :bv := 'C3'
PL/SQL procedure successfully completed.
ops$tkyte%ORA10GR2> /
TREE PAR CHILD_CONS PARENT_CON CHILD PAREN
-------------------- --- ---------- ---------- ----- -----
**C3 P C3_FK_P P_PK X,Y A,B
****P C3 P_FK_C3 C3_UNIQUE A,B X,Y
******C3 C2 C3_FK_C2 C2_PK X,Y,Z X,Y,Z
********C2 C1 C2_FK_C1 C1_PK X,Y,Z X,Y,Z
**C3 C2 C3_FK_C2 C2_PK X,Y,Z X,Y,Z
****C2 C1 C2_FK_C1 C1_PK X,Y,Z X,Y,Z
******C1 P C1_FK_P P_PK X,Y A,B
********P C3 P_FK_C3 C3_UNIQUE A,B X,Y
8 rows selected.
In Addition to above COntent
Bhushan, November 21, 2008 - 1:40 am UTC
Hi Tom,
Above by Parent table i mean the root table, meaning we should be able to get even the parent of the parent and it might also branch to other tables if tehre are more than one FK on a Table.
Also,
Are you coming to Mumbai on 16-17 Dec?
Thanks & Regards,
Bhushan Salgar
November 24, 2008 - 1:40 pm UTC
see the asktom home page - my schedule is there...
heirarchical question
Ian, December 09, 2008 - 1:21 am UTC
Hi Tom,
I have a table that contains some rows with parent child relationships and other rows that are not related. I wish to return all the rows, bringing back any children of the current row before processing the next row
eg
BUBBLE@scrappy > create table t (id number, master_id number);
Table created.
BUBBLE@scrappy >
BUBBLE@scrappy > insert into t values (1, null);
1 row created.
BUBBLE@scrappy > insert into t values (2, null);
1 row created.
BUBBLE@scrappy > insert into t values (3, 1);
1 row created.
BUBBLE@scrappy > insert into t values (4, 3);
1 row created.
BUBBLE@scrappy > insert into t values (5, 4);
1 row created.
BUBBLE@scrappy > insert into t values (6, null);
1 row created.
BUBBLE@scrappy > insert into t values (7, null);
1 row created.
BUBBLE@scrappy > insert into t values (8, 7);
1 row created.
BUBBLE@scrappy > insert into t values (9, 8);
1 row created.
BUBBLE@scrappy > insert into t values (10, 9);
1 row created.
BUBBLE@scrappy >
BUBBLE@scrappy > select * from t;
ID MASTER_ID
---------- ----------
1
2
3 1
4 3
5 4
6
7
8 7
9 8
10 9
10 rows selected.
So i want to return the rows in the order:
Id Level
1 1
3 2
4 3
5 4
2 1
6 1
7 1
8 2
9 3
10 4
But I'm having trouble doing this in a single SQL statement. I've had to do it in a procedure.
BUBBLE@scrappy > declare
2 cursor curGetAllMessages is
3 select connect_by_isleaf cbl
4 ,id
5 ,master_id
6 from t
7 connect by prior id = master_id
8 order by id;
9
10 cursor curGetChildRecs (pId number) is
11 select level
12 ,id
13 ,master_id
14 from t
15 connect by prior id = master_id
16 start with id = pId;
17
18 begin
19 for x in curGetAllMessages loop
20 if x.cbl = 1 and x.master_id is null then
21 -- record is childless
22 dbms_output.put_line('level=1, x='||x.id);
23 elsif x.cbl = 0 AND x.master_id is null then
24 -- record is parent so we need to display the child messages
25 for y in curGetChildRecs(x.id) loop
26 dbms_output.put_line('level='||y.level||', y='||y.id);
27 end loop;
28 end if;
29 end loop;
30 end;
31 /
level=1, y=1
level=2, y=3
level=3, y=4
level=4, y=5
level=1, x=2
level=1, x=6
level=1, y=7
level=2, y=8
level=3, y=9
level=4, y=10
PL/SQL procedure successfully completed.
BUBBLE@scrappy >
Is there a simpler way to do this without looking up the table twice?
Cheers
December 09, 2008 - 2:04 pm UTC
ops$tkyte%ORA10GR2> select rpad('*',2*level,'*') || '-' || id theid, id, master_id, level
2 from t
3 start with master_id is null
4 connect by prior id = master_id
5 order siblings by id
6 /
THEID ID MASTER_ID LEVEL
-------------------- ---------- ---------- ----------
**-1 1 1
****-3 3 1 2
******-4 4 3 3
********-5 5 4 4
**-2 2 1
**-6 6 1
**-7 7 1
****-8 8 7 2
******-9 9 8 3
********-10 10 9 4
10 rows selected.
Ian, December 09, 2008 - 6:25 pm UTC
Many thanks, obvious when you see it
Craig, December 12, 2008 - 11:33 am UTC
Hi Tom
Can you help with a Hierarchical query requirement? This case involves the hierarchy details being stored in a second table (the Children) of the Parent table. The case is People Skills / Competencies, whereby having One skill may mean you have lots of others too.
--------- -------------------
| Skill | ----< | Skill_Hierarchy |
--------- -------------------
create table Skill (
Skill_Id number not null,
Skill_Name varchar2(40) not null,
constraint Skill_Pk primary key (Skill_Id)
);
create table Skill_Hierarchy (
Parent_Skill_Id number not null,
Child_Skill_Id number not null,
constraint Skill_Hierarchy_Pk primary key (Parent_Skill_Id, Child_Skill_Id)
);
alter table Skill_Hierarchy
add constraint Skill_Hierarchy_to_Skill_Fk1 foreign key (Parent_Skill_Id)
references Skill(Skill_Id) enable;
alter table Skill_Hierarchy
add constraint Skill_Hierarchy_to_Skill_Fk2 foreign key (Child_Skill_Id)
references Skill(Skill_Id) enable;
insert into Skill values (1, 'Off-Road - L1');
insert into Skill values (2, 'Off-Road - L2');
insert into Skill values (3, 'Off-Road - L3');
insert into Skill values (11, 'Cooking');
insert into Skill values (12, 'Washing Up');
insert into Skill_Hierarchy values (1, 2);
insert into Skill_Hierarchy values (2, 3);
insert into Skill_Hierarchy values (1, 11);
insert into Skill_Hierarchy values (11, 12);
So
If you have
'Off-Road - L1' you also have:
{'Off-Road - L2', 'Off-Road - L3', 'Cooking', 'Washing Up'}
If you have
'Off-Road - L2' you also have:
{'Off-Road - L3'}
If you have
'Off-Road - L3' thats all you have.
If you have
'Cooking' you also have:
{'Washing Up'}
There is a circularity there as 'Washing up' is achieved by 'Off-Road - L1'
or 'Cooking' independently (I'm testing - not sure if the Data Model is correct yet)
I want to collect the Child/Dependent skills up into a Pl/SQL collection (array) for each Parent skill so need to get something like the following;
Parent_Skill_Id Parent_Skill_Name Child_Skill_Id Child_Skill_Name
--------------- ----------------- -------------- ----------------
1 Off-Road - L1 2 Off-Road - L2
1 Off-Road - L1 3 Off-Road - L3
1 Off-Road - L1 11 Cooking
1 Off-Road - L1 12 Washing Up
2 Off-Road - L2 3 Off-Road - L3
3 Off-Road - L3 Null Null
11 Cooking 12 Washing Up
12 Washing Up Null Null
Still struggling with Connecy By :(
many thanks
Craig
December 12, 2008 - 4:05 pm UTC
ops$tkyte%ORA10GR2> select connect_by_root parent_skill_id pskill_id ,
2 connect_by_root parent_skill_name pskill_name,
3 child_skill_id,
4 (select skill_name from skill where skill_id = X.CHILD_SKILL_ID) child_skill_name
5 from ( select s.skill_name parent_skill_name, s.skill_id parent_skill_id, sh.child_skill_id
6 from skill s, skill_hierarchy sh
7 where s.skill_id = sh.parent_skill_id(+)
8 ) X
9 connect by prior child_skill_id = parent_skill_id and child_skill_id is not null
10 order siblings by parent_skill_id
11 /
PSKILL_ID PSKILL_NAME CHILD_SKILL_ID CHILD_SKILL_NAM
---------- --------------- -------------- ---------------
1 Off-Road - L1 2 Off-Road - L2
1 Off-Road - L1 3 Off-Road - L3
1 Off-Road - L1 11 Cooking
1 Off-Road - L1 12 Washing Up
2 Off-Road - L2 3 Off-Road - L3
3 Off-Road - L3
11 Cooking 12 Washing Up
12 Washing Up
8 rows selected.
parent & child records
ali, December 14, 2008 - 2:15 pm UTC
Tom,
I have an employee table and location table. Each employee has 3 locations with 3 contact numbers & fax numbers. How I can display with single select statement using analytics.
I am using something like this
select e.empno,e.ename,cursor(select l.phone1,l.fax from emp e1,location l where e.empno = l.empno),d.dname from
emp e,dept d where e.dno = d.dno;
pls. advice
December 29, 2008 - 9:39 am UTC
ops$tkyte%ORA9IR2> create table p as select * from scott.emp;
Table created.
ops$tkyte%ORA9IR2> alter table p add constraint p_pk primary key(empno);
Table altered.
ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> create table c
2 ( empno references p,
3 seq number,
4 loc varchar2(6),
5 phone varchar2(8),
6 primary key(empno,seq)
7 )
8 /
Table created.
ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> create sequence s;
Sequence created.
ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> insert into c
2 (empno,seq,loc,phone)
3 select empno, s.nextval, 'loc-' || rownum, 'phone-'||rownum
4 from p,(select level from dual connect by level <= 3)
5 /
42 rows created.
ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> select p.empno, p.ename,
2 max( decode( c.rn, 1, c.loc ) ) loc1,
3 max( decode( c.rn, 2, c.phone ) ) phone1,
4 max( decode( c.rn, 1, c.loc ) ) loc2,
5 max( decode( c.rn, 2, c.phone ) ) phone2,
6 max( decode( c.rn, 1, c.loc ) ) loc3,
7 max( decode( c.rn, 2, c.phone ) ) phone3
8 from p, (select empno, loc, phone, row_number() over (partition by empno order by seq) rn
9 from c) c
10 where p.empno = c.empno
11 group by p.empno, p.ename
12 /
EMPNO ENAME LOC1 PHONE1 LOC2 PHONE2 LOC3 PHONE3
---------- ---------- ------ -------- ------ -------- ------ --------
7900 JAMES loc-12 phone-26 loc-12 phone-26 loc-12 phone-26
7369 SMITH loc-1 phone-15 loc-1 phone-15 loc-1 phone-15
7499 ALLEN loc-2 phone-16 loc-2 phone-16 loc-2 phone-16
7521 WARD loc-3 phone-17 loc-3 phone-17 loc-3 phone-17
7566 JONES loc-4 phone-18 loc-4 phone-18 loc-4 phone-18
7654 MARTIN loc-5 phone-19 loc-5 phone-19 loc-5 phone-19
7698 BLAKE loc-6 phone-20 loc-6 phone-20 loc-6 phone-20
7782 CLARK loc-7 phone-21 loc-7 phone-21 loc-7 phone-21
7788 SCOTT loc-8 phone-22 loc-8 phone-22 loc-8 phone-22
7839 KING loc-9 phone-23 loc-9 phone-23 loc-9 phone-23
7844 TURNER loc-10 phone-24 loc-10 phone-24 loc-10 phone-24
7876 ADAMS loc-11 phone-25 loc-11 phone-25 loc-11 phone-25
7902 FORD loc-13 phone-27 loc-13 phone-27 loc-13 phone-27
7934 MILLER loc-14 phone-28 loc-14 phone-28 loc-14 phone-28
14 rows selected.
re: parent & child records
Stew Ashton, December 29, 2008 - 10:11 am UTC
Tom, did you perhaps mean :
max( decode( c.rn, 1, c.loc ) ) loc1,
max( decode( c.rn, 1, c.phone ) ) phone1,
max( decode( c.rn, 2, c.loc ) ) loc2,
max( decode( c.rn, 2, c.phone ) ) phone2,
max( decode( c.rn, 3, c.loc ) ) loc3,
max( decode( c.rn, 3, c.phone ) ) phone3
...
And welcome back from what I hope was an enjoyable vacation.
December 29, 2008 - 3:42 pm UTC
indeed I did!!!
ops$tkyte%ORA10GR2> select p.empno, p.ename,
2 max( decode( c.rn, 1, c.loc ) ) loc1,
3 max( decode( c.rn, 1, c.phone ) ) phone1,
4 max( decode( c.rn, 2, c.loc ) ) loc2,
5 max( decode( c.rn, 2, c.phone ) ) phone2,
6 max( decode( c.rn, 3, c.loc ) ) loc3,
7 max( decode( c.rn, 3, c.phone ) ) phone3
8 from p, (select empno, loc, phone, row_number() over (partition by empno order by seq) rn
9 from c) c
10 where p.empno = c.empno
11 group by p.empno, p.ename
12 /
EMPNO ENAME LOC1 PHONE1 LOC2 PHONE2 LOC3 PHONE3
---------- ---------- ------ -------- ------ -------- ------ --------
7521 WARD loc-3 phone-3 loc-17 phone-17 loc-31 phone-31
7566 JONES loc-4 phone-4 loc-18 phone-18 loc-32 phone-32
7844 TURNER loc-10 phone-10 loc-24 phone-24 loc-38 phone-38
7876 ADAMS loc-11 phone-11 loc-25 phone-25 loc-39 phone-39
7499 ALLEN loc-2 phone-2 loc-16 phone-16 loc-30 phone-30
7369 SMITH loc-1 phone-1 loc-15 phone-15 loc-29 phone-29
7782 CLARK loc-7 phone-7 loc-21 phone-21 loc-35 phone-35
7839 KING loc-9 phone-9 loc-23 phone-23 loc-37 phone-37
7698 BLAKE loc-6 phone-6 loc-20 phone-20 loc-34 phone-34
7900 JAMES loc-12 phone-12 loc-26 phone-26 loc-40 phone-40
7902 FORD loc-13 phone-13 loc-27 phone-27 loc-41 phone-41
7788 SCOTT loc-8 phone-8 loc-22 phone-22 loc-36 phone-36
7654 MARTIN loc-5 phone-5 loc-19 phone-19 loc-33 phone-33
7934 MILLER loc-14 phone-14 loc-28 phone-28 loc-42 phone-42
14 rows selected.
good catch, thanks!
on hierarchical queries
jvs, May 27, 2009 - 2:34 pm UTC
Dear Tom,
good day to you, I am using hierarchical query in below scenario and I have few queries related to the same if you can please help me on this. We are on 10.2.0.3.0 windows box. I felt that this thread is on hierarchical queries so I have posted here and not raised a new query.
1) if you can please help me in understanding the plan when hierarchical queries are used, if you have already done so in some article/post kindly point me to the same.
2) I am confussed why there's full scan of branchtest table twice in the plan, Full scan of the branchtest table takes place when the account table below is IOT but when it's heap organized then branchtest table is scanned once.
Test case
---------
-- if the account is moved to another branch then the brn_chng and accno_chng will be populated and that record will become the child record
create table account(brn_number varchar2(6) not null, account_no varchar2(8) not null,acc_closed varchar2(1), acc_type varchar2(10),acc_subtype varchar2(10),brn_chng varchar2(6),accno_chng varchar2(8),
primary key (brn_number,account_no)
)organization index
;
-- if the branch is moved then the brn_moved will be populated and record with that value in brn_number will become child record
create table branchtest(brn_number varchar2(6), brn_moved varchar2(6));
-- Create 10 branch records
insert into branchtest select to_char(rownum,'fm000000') brn_number,to_char(rownum,'fm000000') brn_moved from dual connect by level <= 10;
commit;
-- create 100k accounts
insert into account select to_char(decode(mod(rownum,10),0,10,mod(rownum,10)),'fm000000') brn_number,
to_char(rownum,'fm00000000') account_no,decode(mod(rownum,2),0,'Y','N') acc_closed,decode(mod(rownum,4),0,'0000',1,'1111',2,'2222',3,'3333')acc_type,
decode(mod(rownum,4),0,'0000',1,'1111',2,'2222',3,'3333')acc_subtype,null brn_chng,null accno_chng from dual connect by level <= 100000;
commit;
exec dbms_stats.gather_table_stats(user,'BRANCHTEST',estimate_percent => null);
exec dbms_stats.gather_table_stats(user,'ACCOUNT',estimate_percent => null,cascade => true);
-- Find one account for query
select brn_number,account_no from account where account_no = '00050000'
-- query the account table
-- Set autot traceonly
-- if above query returns brn_number to be '000010', for now i have popluated brn_moved with same values as brn_number
select * from account start with account_no = '00005000'
and brn_number = ( select brn_number from branchtest where brn_moved = '000010') connect by prior brn_chng = brn_number and prior accno_chng = account_no;
-- output when account table is IOT
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=1 Bytes=28)
1 0 CONNECT BY (WITH FILTERING)
2 1 INDEX (UNIQUE SCAN) OF 'SYS_IOT_TOP_70752' (INDEX (UNIQU
E)) (Cost=2 Card=1 Bytes=28)
3 2 TABLE ACCESS (FULL) OF 'BRANCHTEST' (TABLE) (Cost=3 Ca
rd=1 Bytes=10)
4 2 TABLE ACCESS (FULL) OF 'BRANCHTEST' (TABLE) (Cost=3 Ca
rd=1 Bytes=10)
5 1 NESTED LOOPS
6 5 BUFFER (SORT)
7 6 CONNECT BY PUMP
8 5 INDEX (UNIQUE SCAN) OF 'SYS_IOT_TOP_70752' (INDEX (UNI
QUE)) (Cost=2 Card=1 Bytes=28)
9 1 INDEX (FULL SCAN) OF 'SYS_IOT_TOP_70752' (INDEX (UNIQUE)
) (Cost=2 Card=1 Bytes=28)
-- output when account table is heap organized
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=1 Bytes=28)
1 0 CONNECT BY (WITH FILTERING)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'ACCOUNT' (TABLE)
3 2 INDEX (UNIQUE SCAN) OF 'SYS_C0012652' (INDEX (UNIQUE))
(Cost=2 Card=1 Bytes=16)
4 3 TABLE ACCESS (FULL) OF 'BRANCHTEST' (TABLE) (Cost=3
Card=1 Bytes=14)
5 1 NESTED LOOPS
6 5 BUFFER (SORT)
7 6 CONNECT BY PUMP
8 5 TABLE ACCESS (BY INDEX ROWID) OF 'ACCOUNT' (TABLE) (Co
st=3 Card=1 Bytes=28)
9 8 INDEX (UNIQUE SCAN) OF 'SYS_C0012652' (INDEX (UNIQUE
)) (Cost=2 Card=1)
10 1 TABLE ACCESS (FULL) OF 'ACCOUNT' (TABLE) (Cost=3 Card=1
Bytes=28)
3) below is the output (chopped after a-time) generated with gather_plan_statistics hint when account table is IOT, if you can please
help me in understanding predicate information
a) for step 2 there's no value for brn_number
b) step 8 we have brn_number = prior null
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time |
-----------------------------------------------------------------------------------------------
|* 1 | CONNECT BY WITH FILTERING| | 1 | | 1 |00:00:00.02 |
|* 2 | INDEX UNIQUE SCAN | SYS_IOT_TOP_70760 | 1 | 1 | 1 |00:00:00.02 |
|* 3 | TABLE ACCESS FULL | BRANCHTEST | 1 | 1 | 1 |00:00:00.01 |
|* 4 | TABLE ACCESS FULL | BRANCHTEST | 1 | 1 | 1 |00:00:00.02 |
| 5 | NESTED LOOPS | | 1 | | 0 |00:00:00.01 |
| 6 | BUFFER SORT | | 1 | | 1 |00:00:00.01 |
| 7 | CONNECT BY PUMP | | 1 | | 1 |00:00:00.01 |
|* 8 | INDEX UNIQUE SCAN | SYS_IOT_TOP_70760 | 1 | 1 | 0 |00:00:00.01 |
| 9 | INDEX FULL SCAN | SYS_IOT_TOP_70760 | 0 | 1 | 0 |00:00:00.01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("BRN_NUMBER"=PRIOR NULL AND "ACCOUNT_NO"=PRIOR NULL)
2 - access("BRN_NUMBER"= AND "ACCOUNT_NO"='00005000')
filter(("ACCOUNT_NO"='00005000' AND "BRN_NUMBER"=))
3 - filter("BRN_MOVED"='000010')
4 - filter("BRN_MOVED"='000010')
8 - access("BRN_NUMBER"=PRIOR NULL AND "ACCOUNT_NO"=PRIOR NULL)
4) tkprof shows branchtest fullscan thrice when account table is IOT but only once when account table is heap organzied.Also there's block in execute phase where as this is select any reasons for this.
a) when account table is IOT
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.01 0 0 0 0
Execute 1 0.00 0.00 0 7 0 0
Fetch 2 0.00 0.00 0 10 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.02 0 17 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 52
Rows Row Source Operation
------- ---------------------------------------------------
1 CONNECT BY WITH FILTERING (cr=17 pr=0 pw=0 time=335 us)
1 INDEX UNIQUE SCAN SYS_IOT_TOP_47796 (cr=17 pr=0 pw=0 time=179 us)(object id 47797)
1 TABLE ACCESS FULL BRANCHTEST (cr=7 pr=0 pw=0 time=48 us)
1 TABLE ACCESS FULL BRANCHTEST (cr=7 pr=0 pw=0 time=71 us)
0 NESTED LOOPS (cr=0 pr=0 pw=0 time=85 us)
1 BUFFER SORT (cr=0 pr=0 pw=0 time=56 us)
1 CONNECT BY PUMP (cr=0 pr=0 pw=0 time=28 us)
0 INDEX UNIQUE SCAN SYS_IOT_TOP_47796 (cr=0 pr=0 pw=0 time=10 us)(object id 47797)
0 INDEX FULL SCAN SYS_IOT_TOP_47796 (cr=0 pr=0 pw=0 time=0 us)(object id 47797)
1 TABLE ACCESS FULL BRANCHTEST (cr=7 pr=0 pw=0 time=48 us)
b) when account table is heap organized
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.00 0 0 0 0
Execute 1 0.00 0.00 0 7 0 0
Fetch 2 0.00 0.00 0 4 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.01 0.00 0 11 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 52
Rows Row Source Operation
------- ---------------------------------------------------
1 CONNECT BY WITH FILTERING (cr=11 pr=0 pw=0 time=390 us)
1 TABLE ACCESS BY INDEX ROWID ACCOUNT (cr=11 pr=0 pw=0 time=188 us)
1 INDEX UNIQUE SCAN SYS_C004535 (cr=10 pr=0 pw=0 time=147 us)(object id 47800)
1 TABLE ACCESS FULL BRANCHTEST (cr=7 pr=0 pw=0 time=89 us)
0 NESTED LOOPS (cr=0 pr=0 pw=0 time=106 us)
1 BUFFER SORT (cr=0 pr=0 pw=0 time=66 us)
1 CONNECT BY PUMP (cr=0 pr=0 pw=0 time=32 us)
0 TABLE ACCESS BY INDEX ROWID ACCOUNT (cr=0 pr=0 pw=0 time=22 us)
0 INDEX UNIQUE SCAN SYS_C004535 (cr=0 pr=0 pw=0 time=9 us)(object id 47800)
0 TABLE ACCESS FULL ACCOUNT (cr=0 pr=0 pw=0 time=0 us)
0 TABLE ACCESS FULL BRANCHTEST (cr=0 pr=0 pw=0 time=0 us)
thanks for your help and time on this.
Regards,
jvs.
May 27, 2009 - 3:54 pm UTC
see all of the steps with CR=0, you can effectively "drop them from your mind, they didn't happen, they are just there - a side effect, artifact of the plan output - but they never happened"
thanks for the answer but some more help.
jvs, May 28, 2009 - 12:10 am UTC
Dear Tom,
thanks for your help and time on this, I belive my queries were not clear but if you can please help me with query no 1 and 3, also with regards to cr=0 in tkprof below is the tkprof output when account table is IOT, in this case the cr is 7 for branchtest table thrice, lines marked with *, I am not able to understand why it is being scanned thrice am i missing something.
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.01 0 0 0 0
Execute 1 0.00 0.00 0 7 0 0
Fetch 2 0.00 0.00 0 10 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.02 0 17 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 52
Rows Row Source Operation
------- ---------------------------------------------------
1 CONNECT BY WITH FILTERING (cr=17 pr=0 pw=0 time=335 us)
1 INDEX UNIQUE SCAN SYS_IOT_TOP_47796 (cr=17 pr=0 pw=0 time=179 us)(object id 47797)
* 1 TABLE ACCESS FULL BRANCHTEST (cr=7 pr=0 pw=0 time=48 us)
* 1 TABLE ACCESS FULL BRANCHTEST (cr=7 pr=0 pw=0 time=71 us)
0 NESTED LOOPS (cr=0 pr=0 pw=0 time=85 us)
1 BUFFER SORT (cr=0 pr=0 pw=0 time=56 us)
1 CONNECT BY PUMP (cr=0 pr=0 pw=0 time=28 us)
0 INDEX UNIQUE SCAN SYS_IOT_TOP_47796 (cr=0 pr=0 pw=0 time=10 us)(object id 47797)
0 INDEX FULL SCAN SYS_IOT_TOP_47796 (cr=0 pr=0 pw=0 time=0 us)(object id 47797)
* 1 TABLE ACCESS FULL BRANCHTEST (cr=7 pr=0 pw=0 time=48 us)
thanks once again for your help and time on this.
Regards,
jvs
May 28, 2009 - 7:18 am UTC
you lost the indentation - however, you know for a fact it was not three times - 7x3 = 21, 21 > 17, 17 is total number of IO's.
the CR= numbers rollup the "tree"
hierarchical query with bind
Lasse, February 06, 2010 - 7:47 am UTC
Hei Tom
Just wanted to ask for your comment on this.
I got a query that works fine using sys_connect_by_path in 8i after setting the "_new_connect_by_enabled=true".
But when using PreparedStatement(In Java) it returns a "ORA-1008" (and yes - I'm setting the values for the parameters). After spending some hours on the problem, I found that a rewriting of the query where i moved the bind-variables inside a GROUP BY and CONNECT BY that worked. Is this a expected behavior or could it be a bug. Here are the queries before and after the rewrite:
Before rewrite (Gives ORA-1008 with PreparedStatement and BIND):SELECT k.kid, k.mdate, k.bdate, k.valdate, k.refnr, k.recordtype, k.bid,
k.messageid, k.arcref, k.amount, ko.valcode, ibt.amounttext,
k.chk_time, k.chk_id, ka.accountalias, k.transcount, k.name
FROM mtext k, accountalias ka, account ko,
(SELECT d.bid, d.mdate, substr(max(replace(sys_connect_by_path(amounttext,'chr(10)'),'chr(10)',' ')),2) amounttext
FROM (SELECT t.bid, t.mdate, t.amounttext,
row_number() OVER (partition by t.bid, t.mdate order by t.bid, t.mdate) ROW#
FROM mtext t, mcontext k
WHERE t.mdate = k.mdate
AND t.bid = k.bid
AND t.mdate >= to_date(?, 'dd.MM.yyyy') AND t.mdate <= to_date(?, 'dd.MM.yyyy')
AND k.kid IN (?)
AND k.amount>0) d
START WITH ROW#=1
CONNECT BY PRIOR bid=bid AND PRIOR mdato=mdato AND PRIOR row# = row# -1
GROUP BY d.bid, d.mdato) ibt
WHERE ka.aid = 15097
AND ka.kid = ko.kid
AND k.kid = ko.kid
AND ibt.mdate = k.mdate
AND ibt.bid = k.bid
ORDER BY k.bdate;
AFTER (Works fine with BIND and PreparedStatement):SELECT b.kid, b.mdate, b.bdate, b.valdate, b.refnr, b.recordtype, b.bid,
b.messageid, b.arcref, b.amount, o.valcode, o.amounttext,
b.chk_time, b.chk_id, o.accountalias, b.transcount, b.name
FROM mcontext b,
(SELECT d.bid, d.mdate, d.valcode, d.accountalias,
substr(max(replace(sys_connect_by_path(amounttext,'chr(10)'),'chr(10)',' ')),2) amounttext
FROM (SELECT t.bid, t.mdate, ko.valcode, ka.accountalias, t.amounttext,
row_number() OVER (partition by t.bid, t.mdate order by t.bid, t.mdate) ROW#
FROM mtext t, mcontext k, accountalias ka, account ko,
WHERE t.mdate = k.mdate
AND t.bid = k.bid
AND ka.kid=ko.kid
AND k.kid=ko.kid
AND t.mdate >= to_date(?, 'dd.MM.yyyy') AND t.mdate <= to_date(?, 'dd.MM.yyyy')
AND k.kid IN (?)
AND ka.aid = ?
AND k.amount>0) d
START WITH ROW#=1
CONNECT BY PRIOR bid=bid AND PRIOR mdato=mdato AND PRIOR row# = row# -1
GROUP BY d.bid, d.mdato) o
WHERE o.mdate = b.mdate
AND o.bid = b.bid
ORDER BY b.bdate;
Bug or feature?
February 09, 2010 - 6:48 pm UTC
... I got a query that works fine using sys_connect_by_path in 8i after setting the "_new_connect_by_enabled=true". ...
do not do that, it was not ready for prime time - that is why it was hidden and not released. You will get "interesting" results from it. So just stop.
Oh wait, you already KNOW THAT.
There cannot be a bug here, the feature does not exist in the ancient software you are using.
hierarchical query with bind continue
Lasse, February 06, 2010 - 11:56 am UTC
Sorry. I see that the two queries I presented was not totaly correct. The second query(AFTER) is missing some columns in the group by, and the first query(BEFORE) is missing a bind variabel after the inline view. This last bind variable seems to be the problem (when its outside the inline view).
The BEFORE query should not be:
...
WHERE ka.aid = 15097
...but - instead:
...
WHERE ka.aid = ?
February 09, 2010 - 6:50 pm UTC
no bug, the feature does not exist in your release. I would strongly encourage you to not use it, you will hit other issues such as "hey, that isn't the right set of rows" as an example.
hierarchical query with bind continue
Lasse, February 10, 2010 - 8:40 am UTC
So then I guess i have to make a function taking an PK from table one as argument, looping through the related rows (not fix count, so cannot decode it) in table two and return concatenated text field. Or do you suggest other options? Have an idea that you might suggest using callable statement and generate entire resultset within a PL/SQL function/package. Considering that the samme application code should run towards both Oracle 8i and 9i, that would actually be a good ide. Then I could still use the hierarchical query in 9i and use a function in 8i. Pays off reading your books ... i guess :-)
February 15, 2010 - 3:43 pm UTC
it will be a procedural approach since 8i just simply did not have that functionality.
Filter Parent Rows if there are Children?
Richard, March 03, 2010 - 2:29 pm UTC
I have a table of hierarchical items and their components. I need to get output from a query that produces the lowest-level components only, excluding intermediary components.
In the following example, item A is made up of 3 components. Two of those components are in turn made up of other components. The two components of A that are made up of components should be excluded. How to accomplish this?
SQL> create table items (item varchar2(2) not null, sub_item varchar2(2), seq_no number not null);
Table created.
SQL> insert into items values ('A','A1',10);
1 row created.
SQL> insert into items values ('A','A2',20);
1 row created.
SQL> insert into items values ('A','A3',30);
1 row created.
SQL> insert into items values ('A1','B1',10);
1 row created.
SQL> insert into items values ('A1','B2',20);
1 row created.
SQL> insert into items values ('A1','B3',30);
1 row created.
SQL> insert into items values ('B2','C1',10);
1 row created.
SQL> insert into items values ('B2','C2',20);
1 row created.
SQL> insert into items values ('A2','D1',10);
1 row created.
SQL> insert into items values ('A2','D2',20);
1 row created.
SQL> insert into items values ('A2','D3',30);
1 row created.
SQL> commit;
Commit complete.
SQL> select level lvl_no,i.*
2 from items i
3 start with item='A'
4 connect by prior sub_item=item
5 order siblings by seq_no;
LVL_NO IT SU SEQ_NO
---------- -- -- ----------
1 A A1 10 <== Exclude
2 A1 B1 10
2 A1 B2 20
3 B2 C1 10
3 B2 C2 20
2 A1 B3 30
1 A A2 20 <== Exclude
2 A2 D1 10
2 A2 D2 20
2 A2 D3 30
1 A A3 30
11 rows selected.
March 04, 2010 - 7:10 am UTC
do you mean like this?
ops$tkyte%ORA10GR2> select rpad('*',2*level,'*')|| item itm, level lvl_no,i.*, connect_by_isleaf
2 from items i
3 where level > 1 OR connect_by_isleaf = 1
4 start with item='A'
5 connect by prior sub_item=item
6 order siblings by seq_no;
ITM LVL_NO IT SU SEQ_NO CONNECT_BY_ISLEAF
--------------- ---------- -- -- ---------- -----------------
****A1 2 A1 B1 10 1
****A1 2 A1 B2 20 0
******B2 3 B2 C1 10 1
******B2 3 B2 C2 20 1
****A1 2 A1 B3 30 1
****A2 2 A2 D1 10 1
****A2 2 A2 D2 20 1
****A2 2 A2 D3 30 1
**A 1 A A3 30 1
9 rows selected.
keep anything that is more than level 1 OR is the terminal leaf node?
Re: Filter Parent Rows if there are Children?
Richard, March 03, 2010 - 2:47 pm UTC
RTFM rules the day! connect_by_isleaf solved the problem, and identified a row I missed on visual inspection to exclude:
LVL_NO ISLEAF IT SU SEQ_NO
---------- ---------- -- -- ----------
2 0 A1 B2 20
Valid connect by?
A reader, March 11, 2010 - 7:40 am UTC
Is it valid when having a hierarchical in a subquery to reference a column as prior?
Like the query below:
SELECT sl.slot2containingcard, SL.SLOTID
FROM slot sl
WHERE sl.slotid IN
(SELECT cs.cardinslot2slot
FROM cardinslot cs
CONNECT BY NOCYCLE cs.cardinslot2slot = PRIOR sl.slotid
START WITH cs.cardinslot2card = :cardid
It is syntactically correct. But what does it semantically mean.
March 11, 2010 - 8:39 am UTC
it is missing a ) so no, it is not correct in that sense.
But in general, yes, it makes "sense".
You are saying:
select * from slot where slotid in (SET)
and it just happens that SET is built using a hierarchy, perfectly normal and acceptable.
What does it semantically mean? It means "return all rows from slot such that slotid is in this SET. This set is ...." - you fill in the ....
Consider this:
select * from dept
where deptno in
(select deptno from emp
start with ename = :X
connect by prior empno = mgr)
That query semantically means
report on all department such that the deptno is in the set of deptnos for all employees that work for the employee whose name is :x
If you put in KING, it would return deptno 10, 20, 30 (but not 40) since everyone works for KING
If you put in BLAKE, you get a smaller set of deptnos
and so on...
Hans-Peter, March 11, 2010 - 12:35 pm UTC
I think that I was not clear enough.
What I meant was
SELECT sl.slot2containingcard, SL.SLOTID
FROM slot sl
WHERE sl.slotid IN
(SELECT cs.cardinslot2slot
FROM cardinslot cs
CONNECT BY NOCYCLE cs.cardinslot2slot = PRIOR sl.slotid <<<
START WITH cs.cardinslot2card = :cardid
The column referenced after the PRIOR is a reference to a column from the table in the main select.
So to change your example:
select * from dept d
where d.deptno in
(select e.deptno from emp e
start with e.ename = :X
connect by prior e.some_column = d.some_other_column)
March 12, 2010 - 2:32 pm UTC
sure it is - the table in the subquery (not the 'main' select, that is an ambiguous term) has access to all of the SL.* columns - all of them. They are constant for an execution of the subquery in this case - but they are there nonetheless.
You might agree with me that this is sensible:
ops$tkyte%ORA11GR2> select *
2 from scott.dept dept
3 where deptno in (select emp.deptno from scott.emp where emp.deptno = dept.deptno)
4 /
I used dept.deptno in the where clause of this correlated subquery.
Now, there is a huge difference between "syntactically correct" and "semantically correct". The above might be syntactically correct, but unless you tell us the QUESTION it was to answer - we cannot tell you if it is semantically sensible (if it in fact answers that question...)
Heirarchical Queries in views, Without START WITH
vikram, April 20, 2010 - 8:09 am UTC
Hi Tom,
I have an interesting question for you based on a real life scenario.
I will try and explain the scenario with the scripts below:
##############
CREATE TABLE ISCT
(
ITEM_NO VARCHAR2(15 CHAR) NOT NULL,
ITEM_TYPE VARCHAR2(3 CHAR) NOT NULL,
ITEM_TYPE_SCO VARCHAR2(3 CHAR) NOT NULL,
ITEM_NO_SCO VARCHAR2(15 CHAR) NOT NULL,
ARTSAL_SEQ_PRIO NUMBER(3) NOT NULL,
ART_SCO_QTY NUMBER(6,3) NOT NULL,
ITEM_SEQ_PRIO NUMBER(3),
PCKL_SEQ_PRIO NUMBER(3),
REG_DATE DATE NOT NULL,
UPD_DATE DATE NOT NULL,
DELETE_DATE DATE,
USER_NO_CHG VARCHAR2(7 CHAR) NOT NULL
);
#########
CREATE TABLE ICONT
(
ITEM_TYPE VARCHAR2(3 CHAR) NOT NULL,
ITEM_NO VARCHAR2(15 CHAR) NOT NULL,
ITEM_TYPE_CHILD VARCHAR2(3 CHAR) NOT NULL,
ITEM_NO_CHILD VARCHAR2(15 CHAR) NOT NULL,
ITEM_QTY_CHILD NUMBER(5) NOT NULL,
REG_DATE DATE NOT NULL,
UPD_DATE DATE NOT NULL,
DELETE_DATE DATE,
II_DATE DATE NOT NULL,
IU_DATE DATE NOT NULL,
SORT_NO NUMBER(5)
);
--
#######
Now inserting rows:
#######
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('15795', 'CCI', 'SCI', '00245905', 25,
1, NULL, NULL, TO_DATE('10/03/2009 15:40:01', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('00245781', 'SCI', 'SCI', '00245905', 1,
1, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('80067553', 'ART', 'SCI', '00245905', 2,
2, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('84178910', 'ART', 'SCI', '00245905', 3,
1, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('70132375', 'ART', 'SCI', '00245905', 4,
8, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('30067555', 'ART', 'SCI', '00245905', 5,
2, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('50067559', 'ART', 'SCI', '00245905', 6,
5, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('14278710', 'ART', 'SCI', '00245905', 7,
2, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('00130092', 'ART', 'SCI', '00245905', 8,
1, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('10110159', 'ART', 'SCI', '00245905', 9,
2, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('30124693', 'ART', 'SCI', '00245905', 10,
4, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('80130093', 'ART', 'SCI', '00245905', 11,
1, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('90110155', 'ART', 'SCI', '00245905', 12,
2, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('60035916', 'ART', 'SCI', '00245905', 13,
2, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('54249810', 'ART', 'SCI', '00245905', 14,
2, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('14180110', 'ART', 'SCI', '00245905', 15,
1, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('97872010', 'ART', 'SCI', '00245905', 16,
1, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('34180010', 'ART', 'SCI', '00245905', 17,
1, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('57871710', 'ART', 'SCI', '00245905', 18,
1, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('40067588', 'ART', 'SCI', '00245905', 19,
2, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('00067590', 'ART', 'SCI', '00245905', 20,
1, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('80067586', 'ART', 'SCI', '00245905', 21,
1, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('20145196', 'ART', 'SCI', '00245905', 22,
2, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('00067585', 'ART', 'SCI', '00245905', 23,
1, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('80124087', 'ART', 'SCI', '00245905', 24,
1, NULL, 1, TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/03/2009 15:46:04', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1008920');
Insert into isct
(ITEM_NO, ITEM_TYPE, ITEM_TYPE_SCO, ITEM_NO_SCO, ARTSAL_SEQ_PRIO,
ART_SCO_QTY, ITEM_SEQ_PRIO, PCKL_SEQ_PRIO, REG_DATE, UPD_DATE,
DELETE_DATE, USER_NO_CHG)
Values
('39809661', 'SPR', 'SCI', '00245781', 1,
1, 1, 1, TO_DATE('10/04/2009 15:24:22', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/04/2009 15:24:22', 'MM/DD/YYYY HH24:MI:SS'),
NULL, '1007193');
Insert into icont (ITEM_TYPE,ITEM_NO,ITEM_TYPE_CHILD,ITEM_NO_CHILD,ITEM_QTY_CHILD,REG_DATE,UPD_DATE,DELETE_DATE,II_DATE,IU_DATE,SORT_NO) values ('SPR','39809661','ART','44178610',1,to_timestamp('23-FEB-07','DD-MON-RR HH24.MI.SSXFF'),to_timestamp('23-FEB-07','DD-MON-RR HH24.MI.SSXFF'),null,to_timestamp('15-NOV-07','DD-MON-RR HH24.MI.SSXFF'),to_timestamp('20-DEC-07','DD-MON-RR HH24.MI.SSXFF'),2);
Insert into icont (ITEM_TYPE,ITEM_NO,ITEM_TYPE_CHILD,ITEM_NO_CHILD,ITEM_QTY_CHILD,REG_DATE,UPD_DATE,DELETE_DATE,II_DATE,IU_DATE,SORT_NO) values ('SPR','39809661','ART','70132375',1,to_timestamp('06-SEP-07','DD-MON-RR HH24.MI.SSXFF'),to_timestamp('06-SEP-07','DD-MON-RR HH24.MI.SSXFF'),null,to_timestamp('15-NOV-07','DD-MON-RR HH24.MI.SSXFF'),to_timestamp('20-DEC-07','DD-MON-RR HH24.MI.SSXFF'),4);
Insert into icont (ITEM_TYPE,ITEM_NO,ITEM_TYPE_CHILD,ITEM_NO_CHILD,ITEM_QTY_CHILD,REG_DATE,UPD_DATE,DELETE_DATE,II_DATE,IU_DATE,SORT_NO) values ('SPR','39809661','ART','74249710',1,to_timestamp('23-FEB-07','DD-MON-RR HH24.MI.SSXFF'),to_timestamp('23-FEB-07','DD-MON-RR HH24.MI.SSXFF'),null,to_timestamp('15-NOV-07','DD-MON-RR HH24.MI.SSXFF'),to_timestamp('20-DEC-07','DD-MON-RR HH24.MI.SSXFF'),3);
Insert into icont (ITEM_TYPE,ITEM_NO,ITEM_TYPE_CHILD,ITEM_NO_CHILD,ITEM_QTY_CHILD,REG_DATE,UPD_DATE,DELETE_DATE,II_DATE,IU_DATE,SORT_NO) values ('SPR','39809661','ART','80067553',1,to_timestamp('23-FEB-07','DD-MON-RR HH24.MI.SSXFF'),to_timestamp('23-FEB-07','DD-MON-RR HH24.MI.SSXFF'),null,to_timestamp('15-NOV-07','DD-MON-RR HH24.MI.SSXFF'),to_timestamp('20-DEC-07','DD-MON-RR HH24.MI.SSXFF'),1);
COMMIT;
##########################################
--------------------------------------------------------------------------------
Now if you create a view as below:
#############
create or replace view test_v
(ITEM_NO, ITEM_TYPE, ITEM_NO_SCO,ITEM_TYPE_SCO)
as
SELECT T.ITEM_NO, T.ITEM_TYPE, CONNECT_BY_ROOT T.ITEM_NO_SCO,T.ITEM_TYPE_SCO
FROM
(
SELECT NVL(C.ITEM_NO_CHILD, I.ITEM_NO) ITEM_NO, NVL(C.ITEM_TYPE_CHILD, I.ITEM_TYPE) ITEM_TYPE, I.ITEM_TYPE_SCO, I.ITEM_NO_SCO
FROM isct I,
icont C
WHERE I.ITEM_NO = C.ITEM_NO(+)
AND I.ITEM_TYPE = C.ITEM_TYPE(+)
) T
CONNECT BY PRIOR T.ITEM_NO = T.ITEM_NO_SCO AND PRIOR T.ITEM_TYPE = T.ITEM_TYPE_SCO;
----
##################
Then run the below query:
##########
select * from test_v where item_no_sco = '00245905'
###########
--
The output is got within a second. But the real scenario is that both table icont and isct have millions of rows. In that case even this small query of the view takes 10minutes.
How do I give the START WITH in the view to make it faster i.e as shown below.
even with millions of rows the output of this comes in seconds:
SELECT T.ITEM_NO, T.ITEM_TYPE, CONNECT_BY_ROOT T.ITEM_NO_SCO,T.ITEM_TYPE_SCO
FROM
(
SELECT NVL(C.ITEM_NO_CHILD, I.ITEM_NO) ITEM_NO, NVL(C.ITEM_TYPE_CHILD, I.ITEM_TYPE) ITEM_TYPE, I.ITEM_TYPE_SCO, I.ITEM_NO_SCO
FROM isct I,
icont C
WHERE I.ITEM_NO = C.ITEM_NO(+)
AND I.ITEM_TYPE = C.ITEM_TYPE(+)
) T
START WITH T.ITEM_NO_SCO = '00245905'
CONNECT BY PRIOR T.ITEM_NO = T.ITEM_NO_SCO AND PRIOR T.ITEM_TYPE = T.ITEM_TYPE_SCO;
########
---
I dont want to use a parametrized view or external variable as then I cannot join with another table for multiple values.
Hope the question is clear. Please excuse the extra columns as I took the script from production and I wanted to give a real life example.
Regards,
Vikram
April 20, 2010 - 9:00 am UTC
... I dont want to use a parametrized view or external variable as then I cannot
join with another table for multiple values.
...
then you won't be doing this. sorry.
Suggest you use a stored procedure that returns a ref cursor instead, in there - you can apply whatever logic you like to construct the appropriate query using bind variables.
A reader, April 28, 2011 - 11:38 pm UTC
I have around 180 tables in my schema for which I am performing data migration. I would like to load the parent tables first and then the child tables. What is the query that will walk through the schema and list the order of migration. Of course, some tables act as both parent and child tables.
I am looking for a hierarchical query to do this.
April 29, 2011 - 8:15 am UTC
Any efficient way to do this? (oracle 9i)
MAX_MIN_CONNECT, May 17, 2011 - 4:05 am UTC
The purpose for the query i trying to churn out is:
If there is child/nested child record for the given ID, get the MAX timestamp for each child record. then get the MIN timestamp for the MAX timestamp of child recordBUT i am stuck at getting the child record.
The subquery below will go thru almost all the records in the table, which is something i want to avoid as the original table has alot of records. Is it possible to make it scan thru less records with the
ultimate parent id provided?
p/s please forgive me if the create table and insert statement has error, as i don't have the privilege to test the statement in my company.
QuerySELECT A.WIPID
FROM (
SELECT T.* ,
SUBSTR(
(SELECT MAX(TO_CHAR(LEVEL,'fm00000')||SYSID)
FROM TBLTRANS A2
WHERE A2.WIPID = 'AAAAAAAA01'
start with A2.SYSID = T.PARENTTXN
connect by prior A2.PARENTTXN = A2.SYSID and prior A2.PARENTTXN <> prior A2.SYSID), 6 ) ultimate_pid
from TBLTRANS T
where T.activity = 'Merge'
) A, TBLTRANS B
where b.SYSID = a.ultimate_pid
and b.activity = 'Merge'
CREATE SQLcreate table tblTrans
(SYSID VARCHAR2(45),
TXNSEQUENCE NUMBER(38),
ACTIVITY VARCHAR2(40),
WIPID VARCHAR2(40),
PARENTTXN VARCHAR2(45),
TXNTIMESTAMP CHAR(18),
INSTEP VARCHAR2(51)
)
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00001', 20000041, 'Split', 'AAAAAAAA01', '00000.00000.00000', '20110402 103348000', '')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00002', 20000042, 'Split', 'AAAAAAAA02', '00000.00000.00001', '20110402 103348000', '')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00003', 20000043, 'Merge', 'AAAAAAAA01', '00000.00000.00000', '20110404 141427000', '')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00004', 20000044, 'Merge', 'AAAAAAAA02', '00000.00000.00003', '20110404 141427000', '')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00005', 20000045, 'Merge', 'AAAAAAAA03', '00000.00000.00003', '20110404 141427000', '')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00006', 20000045, 'Merge', 'AAAAAAAA03', '00000.00000.00000', '20110404 101025000', '')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00007', 20000046, 'Merge', 'AAAAAAAA04', '00000.00000.00006', '20110404 101025000', '')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00008', 20000047, 'Merge', 'AAAAAAAA05', '00000.00000.00000', '20110405 015031000', '')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00009', 20000048, 'Merge', 'AAAAAAAA06', '00000.00000.00008', '20110405 015031000', '')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00010', 20000049, 'Out', 'AAAAAAAA01', '00000.00000.00000', '20110405 040000000', 'Step099')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00011', 20000050, 'Out', 'AAAAAAAA02', '00000.00000.00000', '20110405 050000000', 'Step099')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00012', 20000051, 'Out', 'AAAAAAAA03', '00000.00000.00000', '20110405 060000000', 'Step099')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00013', 20000052, 'Out', 'AAAAAAAA01', '00000.00000.00000', '20110405 070000000', 'Step100')
/
INSERT INTO TBLTRANS VALUES ('00000.00000.00014', 20000053, 'Out', 'AAAAAAAA02', '00000.00000.00000', '20110405 080000000', 'Step100')
/
May 18, 2011 - 9:21 am UTC
he subquery below will go thru almost all the records in the table,
why do you think that? I see a scalar subquery "ULTIMATE_PID" that has a well defined start with and connect by - it won't hit the entire table?
If you get Oracle XE - you too can have a database that you can play with to your hearts content by the way...
Any efficient way to do this? (oracle 9i)
MAX_MIN_CONNECT, May 19, 2011 - 10:58 pm UTC
To clarify, most of the records in the table have Merge activity. For the inner subquery(the
FROM part), the records that doesn't fall under the ultimate parent id for WIPID = 'AAAAAAAA01' but have Merge activity will be returned as well with NULL as the ultimate parent id.
So, I have put in extra criteria as in the
TO part to limit the set of data processed.
FROMSELECT T.* , SUBSTR(
(SELECT MAX(TO_CHAR(LEVEL,'fm00000')||SYSID)
FROM TBLTRANS A2
WHERE A2.WIPID = 'AAAAAAAA01'
start with A2.SYSID = T.PARENTTXN
connect by prior A2.PARENTTXN = A2.SYSID and prior A2.PARENTTXN <> prior
A2.SYSID), 6 ) ultimate_pid
from TBLTRANS T
where T.activity = 'Merge'
TOSELECT T.* , SUBSTR(
(SELECT MAX(TO_CHAR(LEVEL,'fm00000')||SYSID)
FROM TBLTRANS A2
WHERE A2.WIPID = 'AAAAAAAA01'
start with A2.SYSID = T.PARENTTXN
connect by prior A2.PARENTTXN = A2.SYSID and prior A2.PARENTTXN <> prior
A2.SYSID), 6 ) ultimate_pid
from TBLTRANS T
where T.activity = 'Merge'and T.WIPID LIKE 'AAAAAAAA%'
The question is if i do not have an extra column to indicate similarities, is there anything i can do to enhance the query?
e.g. :
previous query if don't have WIPID LIKE 'AAAAAAA%' will returnSYSID WIPID ACTIVITY Ultimate_pid
-------------------------------------------
1 AAAAAAA01 Merge <null>
2 AAAAAAA02 Merge 2
19 BBBBBBB01 Merge <null>
ideal query will returnSYSID WIPID ACTIVITY Ultimate_pid
-------------------------------------------
1 AAAAAAA01 Merge <null>
2 AAAAAAA02 Merge 2
QUERYSELECT A.WIPID
FROM ( <b>SELECT T.* , SUBSTR(
(SELECT MAX(TO_CHAR(LEVEL,'fm00000')||SYSID)
FROM TBLTRANS A2
WHERE A2.WIPID = 'AAAAAAAA01'
start with A2.SYSID = T.PARENTTXN
connect by prior A2.PARENTTXN = A2.SYSID and prior A2.PARENTTXN <> prior
A2.SYSID), 6 ) ultimate_pid
from TBLTRANS T
where T.activity = 'Merge'</b>
<i>and T.WIPID LIKE 'AAAAAAAA%'</i>
) A, TBLTRANS B
where b.SYSID = a.ultimate_pid
and b.activity = 'Merge'
DISPLAY USER ACCESS FORMS IN TREE
Syed Adeel Ali, July 06, 2011 - 2:12 am UTC
Assalam-O-Elikum
Friends I want to show my user access form in hiererichal tree this is my database design which is consist of 4 tables
set_system, set_modules, set_applications, set_forms, emp_access
my parent table is emp_access
and i want to show all the forms with respect to emp_access
if any field modules or forms field is null then its mean
user has access on all forms or modules
or when fields are not null then its mean
user has access only those forms or report where
forms or report define..
CREATE TABLE EMP_ACCESS
EMP_ID NUMBER,
SYS_ID NUMBER,
APP_ID NUMBER,
MOD_ID NUMBER,
FRM_ID NUMBER,
EMP_VIEW CHAR(1),
EMP_INS CHAR(1),
EMP_UP CHAR(1),
EMP_DEL CHAR(1);
INSERT INTO EMP_ACCCESS
(EMP_ID, SYS_ID, EMP_VIEW, EMP_INS, EMP_UP, EMP_DEL)
VALUES
(85, 1, Y, Y, Y, Y);
Create table set_sys
ID NUMBER NOT NULL,
NAME VARCHAR2(40);
INSERT INTO SET_SYS
VALUES
(1, ‘HUMAN RESOURCE MANAGEMENT SYSTEM’);
CREATE TABLE SET_APPLICATIONS
(ID NUMBER NOT NULL,
NAME VARCHAR2(20),
ABRV VARCHAR2(6),
SYS_ID NUMBER);
INSERT INTO SET_APPLICATIONS
VALUES
(4, ‘ADMINISTRATOR’, ‘ADMN’, 1);
INSERT INTO SET_APPLICATIONS
VALUES
(1, ‘PAYROLL’, ‘PAY’, 1);
INSERT INTO SET_APPLICATIONS
VALUES
(2, ‘PERSONNEL’, ‘PER’, 1);
INSERT INTO SET_APPLICATIONS
VALUES
(3, ‘TIMEOFFICE’, ‘TOF’, 1);
CREATE TABLE SET_MODULES
(ID NUMBER NOT NULL,
NAME VARCHAR2(40),
ABRV VARCHAR2(6),
APP_ID NUMBER);
INSERT INTO SET_MODULES
VALUES
(1, ‘FORM FOR PROCESS SALARY’, ‘SPR’, 1);
INSERT INTO SET_MODULES
VALUES
(2, ‘FORM FOR ALLOWANCE’, ‘ALL’, 1);
INSERT INTO SET_MODULES
VALUES
(4, ‘FORM FOR SET INCOME TAX’, ‘ITX’, 1);
INSERT INTO SET_MODULES
VALUES
(5,’ MANUAL EDITING’, MED’, 1);
INSERT INTO SET_MODULES
VALUES
(6, ‘CONVERT DATA TO EXCEL’, ‘CDE’, 1);
INSERT INTO SET_MODULES
VALUES
(13, ‘PERSONNEL MODULES’, ‘PER’, 2);
INSERT INTO SET_MODULES
VALUES
(14, ‘EMPLOYEE INCREMENT / PROMOTION’, ‘EIP’, 2);
INSERT INTO SET_MODULES
VALUES
(15, ‘HIERERICHAL TREE’, ‘HIR’, 2);
INSERT INTO SET_MODULES
VALUES
(16, ‘EXPORT TO EXCEL PER’, ‘ETE’, 2);
INSERT INTO SET_MODULES
VALUES
(17, ’ROSTER (LEAVE, SHIFTS, WEEK OFF)’,’ EMA’, 3);
INSERT INTO SET_MODULES
VALUES
(18, ‘EMPLOYEES MONTHLY ATTENDANCE’, ‘EMS’, 3);
INSERT INTO SET_MODULES
VALUES
(20, ‘REGULAR / DAILY ATTENDANCE’, ‘RAT’, 3);
INSERT INTO SET_MODULES
VALUES
(21, ‘UPLOAD DATA INTO DATABASE’, ‘AOD’, 3);
INSERT INTO SET_MODULES
VALUES
(22, ‘SET COMPANY POLICY’, ‘STD’, 3);
CREATE TABLE SET_FORMS
(ID NUMBER NOT NULL,
NAME VARCHAR2(20),
ABRV VARCHAR2(6),
TYPE CHAR(1),
F_VIEW CHAR(1),
F_INSERT CHAR(1),
F_UPDATE CHAR(1),
F_DELETE CHAR(1),
MOD_ID NUMBER,
PROG_DESC VARCHAR2(200));
/*HERE TYPE R MEANS REPORT
AND TYPE F MEANS FORM*/
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(341, 'FRMADJUST_ATTN_TAX', 'TAXADV','F' ,1 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(241, 'REP_SAL_DTL_2', 'RSDTL2', 'R',1 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(186, 'REP_ACC1', 'RVCHER', 'R' ,1 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(2, 'PAYROLL', 'PAY','F' ,1 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(183, 'EMP_ON_PAYROLL', 'RCUEMP' , 'R' ,1 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(188, 'REP_SAL_SUM', 'RSLSUM' , 'R' ,1 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(3, 'FRMADVANCE', 'ALL' , 'F' ,2 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(282, 'REPALLOWANCE', 'REPALL' , 'R' ,2 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(5, 'INCOME_TAX', 'ITX' , 'F' ,4 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(7, 'FRMMANEDIT', 'MEDIT' , 'F' ,5 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(8, 'FRMEXCELPROCESS', 'ETE' , 'F' ,6 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(321, 'REP_ANVIS', 'REPANV' , 'R' ,13 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(43, 'PERSONNEL', 'PER' , 'F' ,13 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(301, 'IND_DETAIL', 'REPIND' , 'R' ,13 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(181, 'REP_DOC', 'REPDOC' , 'R' ,13 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(184, 'REP_PERSONNEL', 'RDCEMP' , 'R' , 13 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(48, 'EMP_DESGN', 'EDG' , 'F' ,14 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(361, 'REPINCREMENT', 'REPINC' , 'R' ,14 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(53, 'HIERERICHAL', 'HIR' , 'F' ,15 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(58, 'EXPTOEXCEL', 'ETE' , 'F' ,16 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(102, 'FRMLEVSUS', 'LEV' , 'F' ,17 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(101, 'FRMEMPSHIFTS', 'FES' , 'F' ,17 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(207, 'EMP_PERF_HRS', 'REPH1' , 'R' ,18 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(146, 'MNTH_ATT', 'MNATTN' , 'F' ,18 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(206, 'REP_ATT_MONTH', 'RMAABR' , 'R' ,18 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(208, 'EMP_PERF_HRS_2', 'REPH2' , 'R' ,18 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(205, 'REP_EMP_DTL', 'REMATN' , 'R' ,18 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(144, 'TIME_ATTM', 'DATTN' , 'F' ,20 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(261, 'REP_EMPTIMEWISE', 'RESHTW' , 'R' ,20 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(281, 'FRMADJUSTATTN', 'FADATN' , 'F' ,20 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(209, 'REP_EMPSHFT', 'RRATTN' , 'R' ,20 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(161, 'FRMTMP', 'UPLDAT' , 'F' ,21 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(145, 'SET_SETUP', 'SSET' , 'F' ,22 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(143, 'FRMEVALUATION', 'FRMEV' , 'F' ,41 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(141, 'FRMADVANCE', 'FRMADV' , 'F' ,61 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(221, 'CMP_DEPT', 'CCMPDP' , 'F' ,81 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(222, 'FRM_ACCESS', 'ADDFRM' , 'F' ,81 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(224, 'FRM_EMP_ACCESS', 'FEACCS' , 'F',82 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(225, 'FRM_ACCESS', 'ADDFRM' , 'F', 82 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(227, 'FRMSET_DEGREE', 'ADDDEG' , 'F', 83 );
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
INSERT INTO SET_FORMS
(ID, NAME, ABRV, TYPE, MOD_ID)
VALUES
(226, 'FRMOBS', 'ADDOBS' ,'F', 83 );
Thanks & Regards
Syed Adeel Ali
cleanup schema but constraints are in between,
A reader, October 30, 2011 - 5:37 pm UTC
Hello,
I need to drop tables and recreate them. However, each of the tables are interdependent to others. Is there a script to disable relationship constraints (even if the depth is 2 or more levels)?
The purpose of my request is:
Our data modeler releases new version of DDL script which may have a very minor change like change in column order of an index. I could't figure out easily which index is changed. My plan is to install all those DDLs to my temporary schema, figure out the difference between my temporary schema and the real schema and apply the difference (pretty tedious task). When a another release of DDL is released, I need to clean up my temporary schema and install DDL again.
October 31, 2011 - 11:19 am UTC
why your data modeler wouldn't give you a drop/alter/create script to modify the schema is beyond me - that is beyond whacky. No way that would be acceptable (to me). They need to fully document what these changes are and WHY these changes are - so they have to know what the individual changes are (if they do not, please stop calling them a data modeler - just call them trouble).
Are they giving you the full DDL of the entire schema? that is what it sounds like - just drop and recreate your temporary schema
follow up,
A reader, October 31, 2011 - 11:40 am UTC
Thanks. Well, the modeler says ERWin doesn't have the option of generating the delta. So he is giving me the entire DDL script.
I thought about recreating the schema, but in UAT and eventually in Production database, it would be a issue to recreate a user (often). On development box, that is what I am currently doing.
Thanks,
October 31, 2011 - 12:14 pm UTC
the data modeler needs to use a tool that supports - ooh, i don't know - a business? With more than one person?
You only need to do it in development - in development you generate the ALTER script that you'll use in all of the other environments - you ultimately need what this data modeler should be giving you - a verified, complete, documented and checked into your source code control system - script to implement the change for this new version.
I have a question on Hierarchical Query
Maddy, November 02, 2011 - 4:42 pm UTC
CREATE TABLE TEST
(LEVELS NUMBER,
NAME VARCHAR2(65),
ID NUMBER)
INSERT INTO TEST VALUES (1, 'A' , 1);
INSERT INTO TEST VALUES (2, 'B' , 12);
INSERT INTO TEST VALUES (3, 'C' , 123);
INSERT INTO TEST VALUES (4, 'D' , 1234);
INSERT INTO TEST VALUES (4, 'E' , 1235);
INSERT INTO TEST VALUES (4, 'F' , 1236);
INSERT INTO TEST VALUES (3, 'G' , 1237);
INSERT INTO TEST VALUES (4, 'H' , 1238);
INSERT INTO TEST VALUES (4, 'I' , 1239);
INSERT INTO TEST VALUES (1, 'J' , 2001);
INSERT INTO TEST VALUES (2, 'K' , 2002);
INSERT INTO TEST VALUES (3, 'L' , 2003);
INSERT INTO TEST VALUES (4, 'M' , 2004);
INSERT INTO TEST VALUES (4, 'N' , 2005);
INSERT INTO TEST VALUES (1, 'O' , 2100);
INSERT INTO TEST VALUES (2, 'P' , 2101);
INSERT INTO TEST VALUES (3, 'Q' , 2102);
INSERT INTO TEST VALUES (3, 'R' , 2103);
select * from test
I WANT
A/B/C/D,E,F
A/B/G/H,I
J/K/L/M,N
O/P/Q,R
IS IT POSSIBLE
OR CAN I GET THIS :
A/B/C/D
A/B/C/E
A/B/C/F
A/B/G/H
A/B/G/I
J/K/L/M
J/K/L/N
O/P/Q
O/P/R
Please let me know if this is possible . I tried some of your methods But, nothing works or may be I haven't tried enough.
Thanks in advance.
November 03, 2011 - 12:54 am UTC
you'll have to tell me how to put the data together something - how would you do it procedurally.
I've seen lots of peoples concept of "hierarchies" modeled over time - but I've not seen one like yours yet, I do not see how it all goes back together.
The 'normal' way is to just have:
create table t ( id number primary key, parentid references t, data .... );
There would never be a level in there (that is implied data, we get the level based on - well - what level you end up on in the hierarchy). And the parentid pointing to an id makes it rather clear how to assemble the data.
Table for above Query
Maddy, November 02, 2011 - 4:45 pm UTC
Sorry I gave select * instead of the table data.
Here it is :
NUMBER NAME ID
1 A 1
2 B 12
3 C 123
4 D 1234
4 E 1235
4 F 1236
3 G 1237
4 H 1238
4 I 1239
1 J 2001
2 K 2002
3 L 2003
4 M 2004
4 N 2005
1 O 2100
2 P 2101
3 Q 2102
3 R 2103
November 03, 2011 - 12:59 am UTC
that is not table data.
you would have to provide create tables, inserts into that table. something easy for me to cut and paste.
and a lot of detail that describes how your data actually works because it makes no sense to me. I'm hoping we are not connecting by substr's of what look to be numbers - but I'm afraid we are (that would be about the wrongest way I've ever seen to represent a hierarchy ever)
Actual Table and Scripts for Above
Maddy, November 03, 2011 - 2:09 pm UTC
CREATE TABLE TESTING
( "ID" NUMBER,
"PARENT_ID" NUMBER,
"NAME" VARCHAR2(50)
) ;
Insert into TESTING(ID,PARENT_ID,NAME) values (1,0,'A');
Insert into TESTING(ID,PARENT_ID,NAME) values (100,1,'B');
Insert into TESTING(ID,PARENT_ID,NAME) values (200,100,'C');
Insert into TESTING(ID,PARENT_ID,NAME) values (201,200,'D');
Insert into TESTING(ID,PARENT_ID,NAME) values (202,200,'E');
Insert into TESTING(ID,PARENT_ID,NAME) values (300,100,'G');
Insert into TESTING(ID,PARENT_ID,NAME) values (301,300,'H');
Insert into TESTING(ID,PARENT_ID,NAME) values (302,300,'I');
Insert into TESTING(ID,PARENT_ID,NAME) values (2,0,'J');
Insert into TESTING(ID,PARENT_ID,NAME) values (2000,2,'K');
Insert into TESTING(ID,PARENT_ID,NAME) values (3000,2000,'L');
Insert into TESTING(ID,PARENT_ID,NAME) values (3001,3000,'M');
Insert into TESTING(ID,PARENT_ID,NAME) values (3002,3000,'N');
Insert into TESTING(ID,PARENT_ID,NAME) values (3,0,'O');
Insert into TESTING(ID,PARENT_ID,NAME) values (30,3,'P');
Insert into TESTING(ID,PARENT_ID,NAME) values (31,30,'Q');
Insert into TESTING(ID,PARENT_ID,NAME) values (32,30,'R');
there is a unique index on ID Column which is a primary key
ALTER TABLE "TESTING" MODIFY ("ID" NOT NULL ENABLE);
Alter Table "TESTING" Modify ("NAME" Not Null Enable);
SELECT LEVEL,NAME,ID FROM TESTING START WITH PARENT_ID = 0 CONNECT BY PRIOR ID = PARENT_ID;
What I want is :
PARENT CHILDREN
A/B/C D,E,F
A/B/G H,I
J/K/L M,N
O/P Q,R
or
PARENT CHILD1 CHILD2 CHILD3
A/B/C D E F
A/B/G H I NULL
J/K/L M N NULL
O/P Q R NULL
Is it possible..... I am asking it in the right way... Please do let me know
Thanks in advance
November 03, 2011 - 3:11 pm UTC
Ok, so this schema is a BIT DIFFERENT from the other schema (as in, they look nothing remotely like each other at all, not even a teeny tiny bit - so one wonders - what was the other question about ?)
Please describe how you got to your output. Why does A/B/C be a parent of D,E,F. Why isn't A/B a parent of C,D,E,F or why isn't A/B/C/D a parent of E,F instead. What LOGIC drive you to figure out what the parent column of your output is and what goes into the child colum. It looks entirely arbitrary to me.
Maddy, November 03, 2011 - 3:27 pm UTC
I am trying to paste an image But its not allowing me
This is what the actual structure is
A (has child B)
|
B (has children C & G )
|
C has children (D,E,F)
&
G has children (H, I)
J (has child K)
|
K (has child L)
|
L (has children M and N)
O (Has Child P)
|
P has children (Q,R)
Thats how I have the data.......
May be I am not asking it right..... I'll try my best to convey this in a better way...
November 03, 2011 - 3:44 pm UTC
if you need an image to write a specification - you are in the wrong business. We write specifications so we can write code.
So, I'll ask again - what is the specification here.
You wrote:
A (has child B)
|
B (has children C & G )
|
C has children (D,E,F)
&
G has children (H, I)
so what? A (child B) - B has child C & G & D & E & F. So why don't we print out A/B -> C, G, D, E, F
Is the rule "print out the hierarchy until you get to a leaf such that it only has ONE child and all of the children of that child have one child"?
What if
A (has child B)
|
B (has children C & G )
|
C has children (D,E,F) & F has child X and Y
&
G has children (H, I)
What if F has children X and Y - what would the output be then? What if D has child X and Y as well?
What if in addition to that E has child X and Y and Z and M and N
And N has child OO
and M and has children RR and SS?
write a *specfication*, write the rules, write a complete description of what is supposed to happen.
While pictures are worth a thousand words - they also tend to leave out a million other important words. A picture tells the story of a single scene. We need to know the MOVIE.
Missed an Insert Statement
Maddy, November 03, 2011 - 3:28 pm UTC
Insert into TESTING(ID,PARENT_ID,NAME) values (203,200,'F');
Maddy, November 03, 2011 - 4:09 pm UTC
Ok. I'll try my best to explain :
There are these set of users who have permissions to few pages
There is this Table TABLE1 which has ID, Permission Id and Name
There is another Table TABLE2 which has RID and Permission Id (Foreign Key -> TABLE1)
So, TABLE1 would have a particular set of permissions for a particular user role
To simplify it C will have these 3 children D,E,F
For defining a new role I need the A/B/C as Header and D,E,F individually so as to select and add individual role.
I hope it makes sense..... If not I'll try a bit more....
I thought giving the end query would be simpler but Its not...I get it now....
Thanks a lot for your patience.....I appreciate it.....
November 04, 2011 - 1:13 am UTC
you've got to be kidding. How did we get from the review two above, to the one directly above to here? This is *completely and utterly different from the one above* - which in turn has no relationship to the one above it. This is an entirely NEW question.
You have not told me how you know A/B/C is the header and how you know D,E,F are the children.
You have not supplied the real table.
This is as clear as mud in water stirred with a stick.
connect by
A reader, November 29, 2011 - 5:59 pm UTC
Hi Tom,
1.CONNECT BY
2.RECURSIVE SQL -WITH clause
which is faster performance wise when I can use both the approaches to solve a problem ?
(OR) Does it depend ?
November 30, 2011 - 7:11 am UTC
it always depends.
benchmark it. that is what I would do, that is what I do here all of the time.
In general, they should be typically equivalent. Any differences are probably transient (meaning - if you have a with query that blows away a connect by, or vice versa, I would fully expect to see that change in a version or two (or a dot release or two))
Performance??
Dhruva, December 29, 2011 - 8:05 am UTC
Hi Tom,
T1 is a table with approx 1M rows and the given query is running like a dog. The requirement is to identify if a leaf node exists for t3 matching the input variable v2.
In terms of performance, which one is better and why? Will the functionality be any different? Will the second query visit only the subset of matching rows rather than trawling the entire table?
1)
SELECT c1
FROM t1
WHERE c2 = :v1
AND LEVEL > 1 -- Is this good practice?
START WITH t3 = :v2
CONNECT BY PRIOR t3 = t4;
or
2)
SELECT c1
FROM t1
START WITH t3 = :v2
CONNECT BY PRIOR t3 = t4
AND c2 = :v1
AND LEVEL > 1
Is there any merit in adding indexes on t3 & t4?
Thanks
December 29, 2011 - 11:33 am UTC
and the given query is running like a dog.define that, last I looked, greyhounds ran really fast.
What is your definition of slow.
What is 1,000,000 rows - is that 1mb or 100mb or 1gb or 1tb?
Your query does not do this:
The requirement is to identify if a leaf node exists for t3 matching the input variable v2.A leaf node is a node such that it has no child rows. Now, unless your model only goes one level deep - your query does not do that.
How many rows does:
START WITH t3 = :v2
retrieve on average/minimum/maximum?
You cannot just move the "level >1" around, it changes the results:
scott%ORA11GR2> select rpad('*', 2*level, '*')|| ename nm
2 from emp
3 start with mgr is null
4 connect by prior empno = mgr and level > 1;
NM
-------------------------------------------------------------------------------
**KING
****JONES
******SCOTT
********ADAMS
******FORD
********SMITH
****BLAKE
******ALLEN
******WARD
******MARTIN
******TURNER
******JAMES
****CLARK
******MILLER
14 rows selected.
scott%ORA11GR2> select rpad('*', 2*level, '*')|| ename nm
2 from emp
3 where level > 1
4 start with mgr is null
5 connect by prior empno = mgr and level > 1;
NM
-------------------------------------------------------------------------------
****JONES
******SCOTT
********ADAMS
******FORD
********SMITH
****BLAKE
******ALLEN
******WARD
******MARTIN
******TURNER
******JAMES
****CLARK
******MILLER
13 rows selected.
an example like this demands a create table and inserts to work with.
Performance ??
Rajeshwaran Jeyabal, January 02, 2012 - 10:02 pm UTC
The requirement is to identify if a leaf node exists for t3 matching the input variable v2 - Connect_by_isleaf is what you needed if you are on Oracle 10G database.
rajesh@ORA11GR2> variable x number;
rajesh@ORA11GR2>
rajesh@ORA11GR2> exec :x := 7839;
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.09
rajesh@ORA11GR2>
rajesh@ORA11GR2> select emp.*,level
2 from emp
3 where connect_by_isleaf = 1
4 start with empno = :x
5 connect by prior empno = mgr
6 /
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO LEVEL
---------- ---------- --------- ---------- --------- ---------- ---------- ---------- ----------
7876 ADAMS CLERK 7788 12-JAN-83 1100 20 4
7369 SMITH CLERK 7902 17-DEC-80 800 2 20 4
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30 3
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30 3
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30 3
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30 3
7900 JAMES CLERK 7698 03-DEC-81 950 30 3
7934 MILLER CLERK 7782 23-JAN-82 1300 10 3
8 rows selected.
Elapsed: 00:00:00.48
rajesh@ORA11GR2>
rajesh@ORA11GR2>
January 03, 2012 - 11:25 am UTC
or, we might actually wait for them to explain what they meant.
Found the answer (I think)
Dhruva, January 03, 2012 - 5:23 am UTC
You're right about greyhounds, they can do up to 45mph. I should had said a "dog with three legs".
An excerpt from "OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047)" reads:
"It’s theoretically possible to use the WHERE clause to omit rows that will collectively represent an entire branch. But that’s not the same thing as identifying a branch and excluding it as a branch. CONNECT BY is the clause that can identify a branch and exclude it in its entirety.".
Stats from the first query:
FILTER
CONNECT BY WITH FILTERING
TABLE ACCESS BY INDEX ROWID COLLECTIONS
INDEX UNIQUE SCAN PK_COLLECTIONS
NESTED LOOPS
CONNECT BY PUMP
TABLE ACCESS BY INDEX ROWID COLLECTIONS
INDEX RANGE SCAN COLLECTIONS_PARENT_ID_I
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 3 0.05 0.04 2 0 10 0
Execute 3 0.00 0.00 0 0 0 0
Fetch 6 187.09 430.74 370579 2011798 19705257 9
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 12 187.14 430.79 370581 2011798 19705267 9
Stats from the second query:
FILTER
CONNECT BY WITH FILTERING
TABLE ACCESS BY INDEX ROWID COLLECTIONS
INDEX UNIQUE SCAN PK_COLLECTIONS
NESTED LOOPS
CONNECT BY PUMP
TABLE ACCESS BY INDEX ROWID COLLECTIONS
INDEX RANGE SCAN COLLECTIONS_PARENT_ID_I
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 5 0.03 0.02 2 0 4 0
Execute 5 0.00 0.00 0 0 0 0
Fetch 10 0.17 1.32 532 740 0 15
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 20 0.20 1.35 534 740 4 15
The execution paths are exactly the same, but the number of fetches is enormously different.
Please corroborate the findings if you get a chance.
Thanks
PS: Rajeshwaran Jeyabal
I have two input parameters, one decides the "start with" filter, and the other decides the "look for" filter. So I presume it boils down to the same question: where should the "look for" predicate be supplied: in the where clause or the connect by clause? Nevertheless it is a very useful hint. Will try to put it to some use.
Parent and Grand parents of a record.
chandrapandian, July 01, 2013 - 9:38 am UTC
Hi Tom,
My question is very simple. But am not able to find the answer at all in any communities.
My table is
CREATE TABLE TARGET_SUBTARGET
(
TARGET_ID NUMBER(5),
SUB_TARGET_ID NUMBER(5)
);
insert into target_subtarget values ( 1,2);
insert into target_subtarget values ( 1,3);
insert into target_subtarget values ( 2,4);
insert into target_subtarget values ( 2,5);
insert into target_subtarget values (3,6);
insert into target_subtarget values(3,7);
Now the table looks like this
SQL> select * from target_subtarget;
TARGET_ID SUB_TARGET_ID
---------- -------------
1 2
1 3
2 4
2 5
3 6
3 7
6 rows selected.
Now i need to write a querey which can give me a result like this.
TARGET_ID SUB_TARGET_ID
---------- -------------
1 2
1 3
1 4
1 5
1 6
1 7
2 4
2 5
3 6
3 7
The records in bold are inherited records. Can you please help me out to wirte a simple querey?
July 01, 2013 - 9:30 pm UTC
describe the logic behind this. what is an "inherited" record - what sort of rules are you following here?
given your data, this would do it, but - your example is so trivial and your rules of logic are unknown so how knows if it'll work in real life:
ops$tkyte%ORA11GR2> select target_id, connect_by_root( target_id ) , sub_target_id
2 from target_subtarget
3 connect by prior sub_target_id = target_id
4 order by 2, 3
5 /
TARGET_ID CONNECT_BY_ROOT(TARGET_ID) SUB_TARGET_ID
---------- -------------------------- -------------
1 1 2
1 1 3
2 1 4
2 1 5
3 1 6
3 1 7
2 2 4
2 2 5
3 3 6
3 3 7
10 rows selected.
Parent and Grand parents and N Grand parents of a record
chandrapandian, July 01, 2013 - 11:42 am UTC
Hi Tom,
My question is very simple. But am not able to find the answer at all in any communities.
Please ignore the above question and add some more to it.
My table is
CREATE TABLE TARGET_SUBTARGET
(
TARGET_ID NUMBER(5),
SUB_TARGET_ID NUMBER(5)
);
insert into target_subtarget values ( 1,2);
insert into target_subtarget values ( 1,3);
insert into target_subtarget values ( 2,4);
insert into target_subtarget values ( 2,5);
insert into target_subtarget values (3,6);
insert into target_subtarget values(3,7);
insert into target_subtarget values(4,8);
insert into target_subtarget values(5,9);
Now the table looks like this,
TARGET_ID SUB_TARGET_ID
---------- -------------
1 3
1 2
2 4
2 5
3 6
3 7
4 8
5 9
Now i need to write a querey which can give me a result like this.
TARGET_ID SUB_TARGET_ID
---------- -------------
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 92 4
2 5
3 6
3 7
Amine Sekkai, July 01, 2013 - 9:40 pm UTC
Need same kind of result for me
Durga prasad, July 12, 2013 - 8:11 pm UTC
Hi Tom,
this may be the new question but looks similer.I am beginer to sql and one of the senior person asked me to write query for below requirement.
Q) employee name/no and the departments he worked should come in one row/column by seperatin with coma(,). like below
Result
========
Scott,10,20,30
SAM,10,30
I said that it can be done using pl/sql,is there any possibility to get this result with sql alone.
Thanks In advace,
July 16, 2013 - 4:18 pm UTC
search this site for PIVOT.
no create
no inserts
no sql for you from me.
ok, well if we pretend that (select distinct job ename, deptno from scott.emp) is your table - then you can:
ops$tkyte%ORA11GR2> select ename, ltrim(max(sys_connect_by_path( deptno, ',' )),',') scbp
2 from (select ename, deptno, row_number() over (partition by ename order by deptno)rn
3 from (select distinct job ename, deptno from scott.emp)
4 )
5 start with rn = 1
6 connect by prior rn = rn-1 and prior ename = ename
7 group by ename
8 /
ENAME SCBP
--------- ----------------------------------------
CLERK 10,20,30
SALESMAN 30
PRESIDENT 10
MANAGER 10,20,30
ANALYST 20
@Durga prasad
A reader, July 22, 2013 - 1:11 pm UTC
Jess, August 31, 2016 - 10:20 am UTC
Hi Tom,
Most of examples out there build a hierarchy of the same types of entities (managers and employees are both 'people').
I have tables that looks like so:
Departments:
ID NAME PURCH_CODE MGR_ID
1 IT 84723 800
2 SALES 47343 900
...
Employees:
ID NAME START_DATE REVIEW_DATE
100 Bob 20150101 20160303
200 Pam 20160404 20160505
300 Sam 20141212 20160707
400 Jim 20140909 20160202
...
Dept-Grade-Emp map
GRADE_LEVEL DEPT_ID EMP_ID
A12 1 100
A12 1 200
A12 2 300
A12 1 400
B17 2 500
...
The user will always select 1 grade level and wants to see the department and employee data presented like so (ordered by department number and then employee IDs under that):
|Entity|Name | ID |Type |
| 1 | IT | 84723 | DEP |
| 100 | Bob | 100 | EMP |
| 200 | Pam | 200 | EMP |
| 400 | Jim | 400 | EMP |
| 2 | SALES| 47343 | DEP |
| 300 | Sam | 300 | EMP |
...
That's how the business want the result to be displayed. I've tried going at it in a few ways, but am failing. The connection isn't employee-to-employee by manager, but across 2 different entities--it's a hierarchy of departments with employees under it (and joins to other table to pick up other attributes).
Do you have any ideas on how to do it? To make the matters worse, this needs to run on 2 systems (for slightly different data sets), only 1 of which is Oracle (11g). Is there a way to do this without 'connect by'?
Many thanks as always!
September 01, 2016 - 3:43 am UTC
Maybe like this
SQL> create table d ( id int, name varchar2(10), p int );
Table created.
SQL> create table e ( id int, name varchar2(10) );
Table created.
SQL> create table ed ( grade varchar2(10),did int, eid int );
Table created.
SQL>
SQL> insert into d values (1 , 'IT', 12345);
1 row created.
SQL> insert into d values (2 , 'SALES', 56789);
1 row created.
SQL>
SQL> insert into e values (100, 'Bob' );
1 row created.
SQL> insert into e values (200, 'Pam' );
1 row created.
SQL> insert into e values (300, 'Sam' );
1 row created.
SQL> insert into e values (400, 'Jim' );
1 row created.
SQL>
SQL>
SQL> insert into ed values ('A12' , 1 , 100 );
1 row created.
SQL> insert into ed values ('A12' , 1 , 200);
1 row created.
SQL> insert into ed values ('A12' , 2 , 300);
1 row created.
SQL> insert into ed values ('A12' , 1 , 400);
1 row created.
SQL> insert into ed values ('B17' , 2 , 500);
1 row created.
SQL>
SQL>
SQL> select
2 decode(typ,'EMP',' ')||eid entity,
3 name,
4 id,
5 typ
6 from
7 (
8 select ed.did, ed.eid, e.name, e.id, 'EMP' typ
9 from e,ed
10 where e.id = ed.eid
11 and ed.grade = 'A12'
12 union all
13 select d.id, d.id, d.name, d.p, 'DEP' typ
14 from d
15 order by 1,2
16 );
ENTITY NAME ID TYP
------------------------------------------ ---------------------------------------- ---------- ---
1 IT 12345 DEP
100 Bob 100 EMP
200 Pam 200 EMP
400 Jim 400 EMP
2 SALES 56789 DEP
300 Sam 300 EMP
6 rows selected.
SQL>
Jess, August 31, 2016 - 12:04 pm UTC
For the scenario just above, I used the following for the carcass of it:
with result (id, dep, grade, itemtype, seq) as
(
select distinct(dept_id) as id, dept_id as dep, grade_id as grade, 'DEP' as itemtype, 0 as seq
from [map table] where grade_id = 'A17'
union all
select emp_id as id, dept_id as dep, grade_id as grade, 'EMP' as itemtype,
row_number() over (partition by dep_id order by emp_id) as seq
from [map table] where grade_id = 'A17'
)
select (case when itemtype = 'DEP' then id when itemtype = 'EMP' then concat(' ',id) end) id, itemtype, seq from result
order by dep, seq;
This results in
ID ITEMTYPE SEQ
1 DEP 0
100 EMP 1
200 EMP 2
400 EMP 3
2 DEP 0
300 EMP 1
When I try to join the second query in the union to to the emp table to get employee attributes, all emp_ids in the result set above turn to nulls...
I'm also still unsure if this is the best way for doing this to begin with...
Jess, August 31, 2016 - 12:14 pm UTC
Sorry Tom, ignore the bit about nulls IDs, that was user error :)
Jess, September 08, 2016 - 11:07 am UTC
Hi Tom,
Thanks for your answer above. I am trying to turn this query on its head for a different report, but not getting the right results because of non-uniqueness issues.
Departments:
ID NAME PURCH_CODE DESCRIPTION STAFF_COUNT
1 BA PCODE11 Business Analysis 10
2 SALES PCODE12 Sales Department 20
3 DEV PCODE11 Development 30
4 QA PCODE12 Quality Assurance 40
5 ARCH PCODE12 Architecture 50
...
*NOTE*: Purchase codes are not unique to departments.
Employees:
ID NAME START_DATE REVIEW_DATE
100 Bob 20150101 20160303
200 Pam 20160404 20160505
300 Sam 20141212 20160707
400 Jim 20140909 20160202
...
There is an 'infractions' table. Each infraction has a globally unique id.
Each record has an employee, an infraction type, and department ID (under which the emp was at the time,
so an emp can have records spanning multiple depts)
Disciplinary Events
EVENT UID EMP_ID DEP_ID INFR_TYPE
ABC123 100 1 EXX
DEF234 100 1 EXX
GHI211 100 2 EXX
JKL567 100 1 NNN
MNO890 100 3 NNN
PQR111 100 4 NNN
STU345 200 4 NNN
UVW897 200 4 NNN
XYZ010 200 5 NNN
...
A bunch of these will get reviewed on some day and notes will be added. We can assume that all records in the example above are for the same day, so that's what the query will be working on.
The business want a report where, for a given date, the following hierarchy is returned:
* employee (id, name, infraction type, dept purchase code)
- department (id, name, staff count)
- department (id, name, staff count)
In other words, group data by employee, infraction type and their dept purchase code (so show the 'parent' line with emp.employee_id/name, disciplinary.infraction_type, dept.purchase_code) and, for each employee, show their departments (from infraction table) and dept name/staff counts.
For the example above, we would expect the data to look as follows:
| ID | NAME | INFR| PUR_CODE| STAFFCT|
| 100 | BOB | EXX | PCODE11 | |
| 1 | BA | | | 10 |
| 100 | BOB | EXX | PCODE12 | |
| 2 | SALES| | | 20 |
| 100 | BOB | NNN | PCODE11 | |
| 1 | BA | | | 10 |
| 3 | DEV | | | 30 |
| 100 | BOB | NNN | PCODE12 | |
| 4 | QA | | | 40 |
| 200 | PAM | NNN | PCODE12 | |
| 4 | BA | | | 10 |
| 5 | ARCH | | | 50 |
The problem is the same departments have to show up multiple times in the result set... In the department part of 'union all', if I push all departments through, then I get duplicates. For example emp=1 has 3 EXX infractions, 2 of which are in dept=1, but I only want a distinct row per department. But if I push through distinct set of departments, then dept=1 doesn't show up for the same employee later on where infraction is NNN...
Could you help? Not sure where I am going wrong...
Thank you as always.
September 08, 2016 - 4:41 pm UTC
The data you've supplied doesn't quite seem to match the output you're expecting.
In any case, here's one way to tackle the problem:
- Join all the tables together
- Unpivot the columns, so you get rows for the employee and department columns
- Filter the results so you only have one row / employee infraction code
Because the columns don't fully line up, you'll need to create some fake columns to unpivot by. These will just be null.
CREATE TABLE dep (ID int, NAME varchar2(5), PURCH_CODE varchar2(7), DESCRIPTION varchar2(17), STAFF_COUNT int)
;
INSERT INTO dep VALUES (1, 'BA', 'PCODE11', 'Business Analysis', 10);
INSERT INTO dep VALUES (2, 'SALES', 'PCODE12', 'Sales Department', 20);
INSERT INTO dep VALUES (3, 'DEV', 'PCODE11', 'Development', 30);
INSERT INTO dep VALUES (4, 'QA', 'PCODE12', 'Quality Assurance', 40);
INSERT INTO dep VALUES (5, 'ARCH', 'PCODE12', 'Architecture', 50);
CREATE TABLE emp (ID int, NAME varchar2(3), START_DATE int, REVIEW_DATE int);
INSERT INTO emp VALUES (100, 'Bob', 20150101, 20160303);
INSERT INTO emp VALUES (200, 'Pam', 20160404, 20160505);
INSERT INTO emp VALUES (300, 'Sam', 20141212, 20160707);
INSERT INTO emp VALUES (400, 'Jim', 20140909, 20160202);
CREATE TABLE inf (EVENT_UID varchar2(6), EMP_ID int, DEP_ID int, INFR_TYPE varchar2(3));
INSERT INTO inf VALUES ('ABC123', 100, 1, 'EXX');
INSERT INTO inf VALUES ('DEF234', 100, 1, 'EXX');
INSERT INTO inf VALUES ('GHI211', 100, 2, 'EXX');
INSERT INTO inf VALUES ('JKL567', 100, 1, 'NNN');
INSERT INTO inf VALUES ('MNO890', 100, 3, 'NNN');
INSERT INTO inf VALUES ('PQR111', 100, 4, 'NNN');
INSERT INTO inf VALUES ('STU345', 200, 4, 'NNN');
INSERT INTO inf VALUES ('UVW897', 200, 4, 'NNN');
INSERT INTO inf VALUES ('XYZ010', 200, 5, 'NNN');
select id, name, infr, pcode, ct, rnd from (
select row_number() over (partition by rk, v order by rk) rne,
row_number() over (partition by rk, v, name order by rk) rnd,
s.*
from (
select emp.id eid, emp.name ename, inf.infr_type, null e_count,
d.id did, d.name dname, d.purch_code, d.staff_count,
null dcode, null dtype,
rank() over (order by emp.id, inf.infr_type) rk
from emp
join inf
on emp.id = inf.emp_id
join dep d
on d.id = inf.dep_id
)
unpivot ((id, name, infr, pcode, ct) for v in (
(eid, ename, infr_type, purch_code, e_count) as 'E',
(did, dname, dtype, dcode, staff_count) as 'D'
)
) s
)
where case when v = 'E' then 1 else rne end = rne
and case when v = 'D' then 1 else rnd end = rnd
order by rk, v desc;
ID NAME INFR PCODE CT RND
100 Bob EXX PCODE11 1
2 SALES 20 1
1 BA 10 1
100 Bob NNN PCODE12 1
4 QA 40 1
1 BA 10 1
3 DEV 30 1
200 Pam NNN PCODE12 1
5 ARCH 50 1
4 QA 40 1
Chris
Hierarchical tree structure- Connect by prior with two tables
Sabarinath, August 16, 2023 - 6:07 am UTC
I have a view and table EG_OFFICE_ORGANIZATION_UNITS_V and EG_OFFICE_POSITIONS_T
CREATE OR REPLACE FORCE EDITIONABLE VIEW "EG_OFFICE_ORGANIZATION_UNITS_V
("ORG_UNIT_ID", "ORG_UNIT_NAME", "ORG_UNIT_SHORTNAME", "PARENT_ORGUNIT_ID",
"ENTITY_TYPE_ID", "ENTITY_NAME", "HIERARCHY") AS
select EOU.ORG_UNIT_ID,
EOU.ORG_UNIT_NAME,
EOU.ORG_UNIT_SHORTNAME,
EOU.PARENT_ORGUNIT_ID,
EOU.ENTITY_TYPE_ID,
EET.ENTITY_NAME,
EET.HIERARCHY
from EG_OFFICE_ORGANIZATION_UNITS_T EOU,
EG_OFFICE_ENTITY_TYPES_T EET
where EOU.ENTITY_TYPE_ID = EET.ENTITY_TYPE_ID
and EOU.STATUS = 'Y'
order by EET.HIERARCHY, EOU.ORG_UNIT_NAME
with this data in it:
insert into EG_OFFICE_ORGANIZATION_UNITS_V values
('5','Govt.of Tamil Nadu','GOTN','-','1','Govt. of Tamil Nadu','10');
insert into EG_OFFICE_ORGANIZATION_UNITS_V values
('6','Chief Secretary','CS','5','5','Secretariat','20');
insert into EG_OFFICE_ORGANIZATION_UNITS_V values
('7','Rural and Pachayat Raj','RD','6','2','Department','30');
insert into EG_OFFICE_ORGANIZATION_UNITS_V values
('12','Information Technology and Digital Services','IT&DS','6','2','Department','30');
insert into EG_OFFICE_ORGANIZATION_UNITS_V values
('17','Electronics Corporation of Tamilnadu','ELCOT','12','3','Directorate','40');
insert into EG_OFFICE_ORGANIZATION_UNITS_V values
('16','Tamil Arasu Cable Operator ','TACO','12','3','Directorate','40');
insert into EG_OFFICE_ORGANIZATION_UNITS_V values
('31','Directorate of e-Governance','DOEG','14','7','Wing','50');
CREATE OR REPLACE EG_OFFICE_POSITIONS_T TABLE(POSITION_ID,POSITION_NAME,ORG_ID,ORGUNIT_ID);
with this data in it:
insert into EG_OFFICE_POSITIONS_T values ('15','Manager','1','6');
insert into EG_OFFICE_POSITIONS_T values ('12','General Manager','1','7');
insert into EG_OFFICE_POSITIONS_T values ('13','Assistant Manager','1','7');
insert into EG_OFFICE_POSITIONS_T values ('15','Principal Secretary','1','13');
insert into EG_OFFICE_POSITIONS_T values ('2','Director-TNeGA','1','15');
insert into EG_OFFICE_POSITIONS_T values ('16','Test Admin','1','16');
OUTPUT :
I need Hierarchical tree structure for these EG_OFFICE_ORGANIZATION_UNITS_V view and EG_OFFICE_POSITIONS_T table with connect by prior.
If I click ORG_UNIT_NAME it will come POSITION_NAME under ORG_UNIT_NAME like tree structure..
eg for Tree:
Govt.of Tamil Nadu
|
Chief Secretary
|--> Manager
Rural and Pachayat Raj
|--> General Manager
Here is my tried code :
SELECT
CASE
WHEN connect_by_isleaf = 1 THEN 0
WHEN level = 1 THEN 1
ELSE -1
END AS status,
level,
org."ORG_UNIT_NAME" AS title,
NULL AS icon,
-- org."ORG_UNIT_ID" AS value,
pos."POSITION_ID" AS VALue, -- Include position name
NULL AS tooltip,
NULL AS link
FROM
"#OWNER#"."EG_OFFICE_ORGANIZATION_UNITS_V" org
LEFT JOIN
"#OWNER#"."EG_OFFICE_POSITIONS_V" pos
ON
org."ORG_UNIT_ID" = pos."ORGUNIT_ID" -- Adjust the join condition based on your schema
START WITH
org."PARENT_ORGUNIT_ID" IS NULL
CONNECT BY PRIOR org."ORG_UNIT_ID" = org."PARENT_ORGUNIT_ID"
ORDER SIBLINGS BY org."ORG_UNIT_NAME";
August 22, 2023 - 12:41 pm UTC
Thanks for the scripts; we need the complete statements to re-create this though. That includes DDL for all the tables, not just the view on top of them!
Also I'm unclear exactly what format this output format means:
Govt.of Tamil Nadu
|
Chief Secretary
|--> Manager
Rural and Pachayat Raj
|--> General Manager
What does the pipe represent? Is this all one row or separate rows? How does this compare to the output the statement you provided gives?