获取 Oracle Sql 中链(树)中任何元素的最顶层元素
Get the top most element for any element in chain (tree) in Oracle Sql
考虑以下具有一些节点的结构:
1
/\
2 3
| |
4 5
| |
6 7
|
8
或
with mydata as (
select 8 id ,6 id_before, 400 datum from dual union all
select 6,4, 300 from dual union all
select 4, 2, 200 from dual union all
select 2,1, 10 from dual union all
select 3, 1, 60 from dual union all
select 5, 3, 800 from dual union all
select 7, 5, 900 from dual
)
现在给定节点的 id
我想得到 root node id
例如for node 7
root note 1
, for 5
root node 1
for 4
root node 1
etc.
我试过这样的事情:
select id, id_before,datum, SYS_CONNECT_BY_PATH(id_before,'/') as path,
SYS_CONNECT_BY_PATH(datum,'/') as datapath,
level,
CONNECT_BY_ROOT id_before
from mydata
where id=7
connect by id_before = prior id
结果令人失望:
7 5 900 /1/3/5 /60/800/900 3 1
7 5 900 /3/5 /800/900 2 3
7 5 900 /5 /900 1 5
关于如何解决这个问题有什么想法吗?
谢谢。
您可以使用 CONNECT_BY_ISLEAF
作为过滤器来查找根元素:
Oracle 设置:
CREATE TABLE mydata ( id, id_before, datum ) as
select 8, 6, 400 from dual union all
select 6, 4, 300 from dual union all
select 4, 2, 200 from dual union all
select 2, 1, 10 from dual union all
select 3, 1, 60 from dual union all
select 5, 3, 800 from dual union all
select 7, 5, 900 from dual;
查询:
SELECT CONNECT_BY_ROOT( id ) AS id,
id_before AS root_id,
SYS_CONNECT_BY_PATH( id, ',' ) || ',' || id_before AS path
FROM mydata
WHERE CONNECT_BY_ISLEAF = 1
CONNECT BY id = PRIOR id_before;
输出:
ID | ROOT_ID | PATH
-: | ------: | :---------
2 | 1 | ,2,1
3 | 1 | ,3,1
4 | 1 | ,4,2,1
5 | 1 | ,5,3,1
6 | 1 | ,6,4,2,1
7 | 1 | ,7,5,3,1
8 | 1 | ,8,6,4,2,1
db<>fiddle here
今天这个话题对我帮助很大。
需要找到一种方法在中间逐项获取整棵树。
在这里分享结果是公平的,即使在接受答案 2 年后也是如此。
create table ref (id number not null, prvni varchar2(1), druhy varchar2(1));
insert into ref (id, prvni, druhy) values (1, 'B', 'A');
insert into ref (id, prvni, druhy) values (2, 'C', 'A');
insert into ref (id, prvni, druhy) values (3, 'D', 'C');
insert into ref (id, prvni, druhy) values (4, 'E', 'A');
insert into ref (id, prvni, druhy) values (5, 'F', 'C');
insert into ref (id, prvni, druhy) values (6, 'G', 'F');
insert into ref (id, prvni, druhy) values (7, 'x', 'y');
insert into ref (id, prvni, druhy) values (8, 'z', 'v');
insert into ref (id, prvni, druhy) values (9, 'w', 'u');
create table zpr (pismeno varchar2(1), typ varchar2(6));
insert into zpr (pismeno, typ) values ('A', 'ORDERS');
insert into zpr (pismeno, typ) values ('B', 'ORDRSP');
insert into zpr (pismeno, typ) values ('C', 'DESADV');
insert into zpr (pismeno, typ) values ('D', 'RECADV');
insert into zpr (pismeno, typ) values ('E', 'RETANN');
insert into zpr (pismeno, typ) values ('F', 'INVOIC');
insert into zpr (pismeno, typ) values ('G', 'INVOIC');
insert into zpr (pismeno, typ) values ('x', 'APERAK');
insert into zpr (pismeno, typ) values ('y', 'APERAK');
insert into zpr (pismeno, typ) values ('z', 'APERAK');
insert into zpr (pismeno, typ) values ('u', 'APERAK');
insert into zpr (pismeno, typ) values ('v', 'APERAK');
insert into zpr (pismeno, typ) values ('w', 'APERAK');
-- recursion
WITH rcte(prvni,druhy,typ,lvl) AS
(SELECT r1.prvni, r1.druhy, a1.typ, 1 AS lvl
FROM ref r1, zpr a1
WHERE (r1.prvni = 'B' OR r1.druhy = 'B')
AND a1.pismeno = r1.druhy
UNION ALL
SELECT r2.prvni, r2.druhy, a2.typ, lvl + 1 AS lvl
FROM ref r2
INNER JOIN zpr a2
ON a2.pismeno = r2.druhy
INNER JOIN rcte rc
ON r2.prvni = rc.druhy),
orders AS
(SELECT * FROM rcte WHERE typ = 'ORDERS')
SELECT prvni,
z1.typ prvni_typ,
connect_by_root(druhy) AS druhy,
z2.typ druhy_typ,
sys_connect_by_path(druhy, ' => ') || ' => ' || prvni AS path,
sys_connect_by_path(z2.typ, ' => ') AS typy
FROM ref, zpr z1, zpr z2
WHERE ref.prvni = z1.pismeno
AND ref.druhy = z2.pismeno
--and CONNECT_BY_ISLEAF = 1
CONNECT BY PRIOR prvni = druhy
START WITH ref.druhy IN (SELECT druhy FROM orders);
考虑以下具有一些节点的结构:
1
/\
2 3
| |
4 5
| |
6 7
|
8
或
with mydata as (
select 8 id ,6 id_before, 400 datum from dual union all
select 6,4, 300 from dual union all
select 4, 2, 200 from dual union all
select 2,1, 10 from dual union all
select 3, 1, 60 from dual union all
select 5, 3, 800 from dual union all
select 7, 5, 900 from dual
)
现在给定节点的 id
我想得到 root node id
例如for node 7
root note 1
, for 5
root node 1
for 4
root node 1
etc.
我试过这样的事情:
select id, id_before,datum, SYS_CONNECT_BY_PATH(id_before,'/') as path,
SYS_CONNECT_BY_PATH(datum,'/') as datapath,
level,
CONNECT_BY_ROOT id_before
from mydata
where id=7
connect by id_before = prior id
结果令人失望:
7 5 900 /1/3/5 /60/800/900 3 1
7 5 900 /3/5 /800/900 2 3
7 5 900 /5 /900 1 5
关于如何解决这个问题有什么想法吗?
谢谢。
您可以使用 CONNECT_BY_ISLEAF
作为过滤器来查找根元素:
Oracle 设置:
CREATE TABLE mydata ( id, id_before, datum ) as
select 8, 6, 400 from dual union all
select 6, 4, 300 from dual union all
select 4, 2, 200 from dual union all
select 2, 1, 10 from dual union all
select 3, 1, 60 from dual union all
select 5, 3, 800 from dual union all
select 7, 5, 900 from dual;
查询:
SELECT CONNECT_BY_ROOT( id ) AS id,
id_before AS root_id,
SYS_CONNECT_BY_PATH( id, ',' ) || ',' || id_before AS path
FROM mydata
WHERE CONNECT_BY_ISLEAF = 1
CONNECT BY id = PRIOR id_before;
输出:
ID | ROOT_ID | PATH -: | ------: | :--------- 2 | 1 | ,2,1 3 | 1 | ,3,1 4 | 1 | ,4,2,1 5 | 1 | ,5,3,1 6 | 1 | ,6,4,2,1 7 | 1 | ,7,5,3,1 8 | 1 | ,8,6,4,2,1
db<>fiddle here
今天这个话题对我帮助很大。 需要找到一种方法在中间逐项获取整棵树。 在这里分享结果是公平的,即使在接受答案 2 年后也是如此。
create table ref (id number not null, prvni varchar2(1), druhy varchar2(1));
insert into ref (id, prvni, druhy) values (1, 'B', 'A');
insert into ref (id, prvni, druhy) values (2, 'C', 'A');
insert into ref (id, prvni, druhy) values (3, 'D', 'C');
insert into ref (id, prvni, druhy) values (4, 'E', 'A');
insert into ref (id, prvni, druhy) values (5, 'F', 'C');
insert into ref (id, prvni, druhy) values (6, 'G', 'F');
insert into ref (id, prvni, druhy) values (7, 'x', 'y');
insert into ref (id, prvni, druhy) values (8, 'z', 'v');
insert into ref (id, prvni, druhy) values (9, 'w', 'u');
create table zpr (pismeno varchar2(1), typ varchar2(6));
insert into zpr (pismeno, typ) values ('A', 'ORDERS');
insert into zpr (pismeno, typ) values ('B', 'ORDRSP');
insert into zpr (pismeno, typ) values ('C', 'DESADV');
insert into zpr (pismeno, typ) values ('D', 'RECADV');
insert into zpr (pismeno, typ) values ('E', 'RETANN');
insert into zpr (pismeno, typ) values ('F', 'INVOIC');
insert into zpr (pismeno, typ) values ('G', 'INVOIC');
insert into zpr (pismeno, typ) values ('x', 'APERAK');
insert into zpr (pismeno, typ) values ('y', 'APERAK');
insert into zpr (pismeno, typ) values ('z', 'APERAK');
insert into zpr (pismeno, typ) values ('u', 'APERAK');
insert into zpr (pismeno, typ) values ('v', 'APERAK');
insert into zpr (pismeno, typ) values ('w', 'APERAK');
-- recursion
WITH rcte(prvni,druhy,typ,lvl) AS
(SELECT r1.prvni, r1.druhy, a1.typ, 1 AS lvl
FROM ref r1, zpr a1
WHERE (r1.prvni = 'B' OR r1.druhy = 'B')
AND a1.pismeno = r1.druhy
UNION ALL
SELECT r2.prvni, r2.druhy, a2.typ, lvl + 1 AS lvl
FROM ref r2
INNER JOIN zpr a2
ON a2.pismeno = r2.druhy
INNER JOIN rcte rc
ON r2.prvni = rc.druhy),
orders AS
(SELECT * FROM rcte WHERE typ = 'ORDERS')
SELECT prvni,
z1.typ prvni_typ,
connect_by_root(druhy) AS druhy,
z2.typ druhy_typ,
sys_connect_by_path(druhy, ' => ') || ' => ' || prvni AS path,
sys_connect_by_path(z2.typ, ' => ') AS typy
FROM ref, zpr z1, zpr z2
WHERE ref.prvni = z1.pismeno
AND ref.druhy = z2.pismeno
--and CONNECT_BY_ISLEAF = 1
CONNECT BY PRIOR prvni = druhy
START WITH ref.druhy IN (SELECT druhy FROM orders);