I have a table, SELECT * FROM data
id pred name visual link, for your convenience
--------------------
1 null One
20 null Two <--+
21 20 Three -^
30 null Four <--+
31 30 Five -^ <--+
32 31 Six -^
In which the rows are connected via the pred
column to the id
column. They form only chains and not a tree -- each node has only one or zero successors (if that's important).
I want to add a column init
to the query where the very first element in the chain is shown , ie
id pred name init initname
---------------------------------
1 null One 1 One
20 null Two 20 Two
21 20 Three 20 Two
30 null Four 30 Four
31 30 Five 30 Four
32 31 Six 30 Four
pred=null
also show null
for init
. initname
column is completely optional and I show it here only for demonstration, I only need the id
. From what I gathered about the connect by
clause I managed a somewhat reverse result, where for each "root" its "child" nodes are listed. I don't know how to "turn the query around".
SELECT id, pred, CONNECT_BY_ROOT id init, LEVEL, CONNECT_BY_ISLEAF "IsLeaf"
FROM data
CONNECT BY PRIOR pred=id
ORDER BY id, level;
Gives the result
id pred init lvl isLeaf
--------------------------
1 null 1 1 1
20 null 20 1 1
20 null 21 2 1
21 20 21 1 0
30 null 30 1 1
30 null 31 2 1
30 null 32 3 1
31 30 31 1 0
31 30 32 2 0
32 31 32 1 0
which somehow represents the the whole "tree", obviously. But alas, "the wrong way around". I'd need for example
id pred init lvl isLeaf
21 20 0 ? ?
instead of
id pred init lvl isLeaf
21 20 21 1 0
If you need data, here is the example data:
create table data ( id number primary key, pred number, name varchar2(100) );
insert into data(id,pred,name) values( 1 , null , 'One');
insert into data(id,pred,name) values( 20, null , 'Two');
insert into data(id,pred,name) values(21, 20 , 'Three');
insert into data(id,pred,name) values(30, null , 'Four');
insert into data(id,pred,name) values(31, 30 , 'Five');
insert into data(id,pred,name) values(32, 31 , 'Six');
SQL> select id
2 , pred
3 , name
4 , connect_by_root id init
5 , connect_by_root name initname
6 , sys_connect_by_path(id,' -> ') scbp
7 from data
8 connect by prior id = pred
9 start with pred is null
10 /
ID PRED NAME INIT INITNAME SCBP
---------- ---------- ---------- ---------- ---------- ------------------------------
1 One 1 One -> 1
20 Two 20 Two -> 20
21 20 Three 20 Two -> 20 -> 21
30 Four 30 Four -> 30
31 30 Five 30 Four -> 30 -> 31
32 31 Six 30 Four -> 30 -> 31 -> 32
6 rows selected.
Please try to use following expression to get name of the root element:
substr(SYS_CONNECT_BY_PATH(name, '/'), instr(SYS_CONNECT_BY_PATH(name, '/'), '/', -1)+1)
Replace delimiter '/' if needed.
SELECT id, pred, CONNECT_BY_ROOT id init, LEVEL, CONNECT_BY_ISLEAF "IsLeaf",
substr(SYS_CONNECT_BY_PATH(name, '/'), instr(SYS_CONNECT_BY_PATH(name, '/'), '/', -1)+1)
FROM data
CONNECT BY PRIOR pred=id
-- START WITH pred is NULL --???
ORDER BY id, level;
You probably need to add START WITH clause as well
I managed to get the result with a nested query.
select id, pred, name, init, (select name from data where id=init) initname
from (
SELECT d1.*
, (select d2.id init
from data d2
where CONNECT_BY_ISLEAF=1 start with d2.id=d1.id CONNECT BY PRIOR pred=id) init
FROM data d1
ORDER BY id ) xdata
;
As you can see, to get the initname
I need an additional subquery this way. This is not perfect, but good enough -- the query is on the PK.
id pred Name init initname
------------------------------
1 One 1 One
20 Two 20 Two
21 20 Three 20 Two
30 Four 30 Four
31 30 Five 30 Four
32 31 Six 30 Four
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.