获取 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);

Here's the fiddle: http://sqlfiddle.com/#!4/5a3181/38