如何连接双方

时间:2019-08-20 14:00:10

标签: sql oracle oracle12c connect-by

我正在尝试获取ID列表的所有后代。 就像目录树一样,其中ID列表是具有访问权限的目录,包括子目录。要导航到文件夹,我还需要提升。

我尝试了UNION提升者和后代,但是如果这样做,我将没有正确的SYS_CONNECT_BY_PATH结果,因为提升者是颠倒的。

我的表有一个ID,名称和Parent_ID。

是否有机会进行这项工作?

3 个答案:

答案 0 :(得分:1)

您可以编写自己的connect_by_path并使用CTE修改其行为:

with c(id, name, parent_id, direction, list) as (
  select id, name, parent_id, 0, name from t where name = 'A1'
  union all
  select t.id, t.name, t.parent_id, 
         case t.parent_id when c.id then 1 else 2 end,
         case when t.parent_id = c.id 
              then c.name||'/'||t.name
              else t.name||'/'||c.name
         end
    from c join t on (direction in (0, 1) and t.parent_id = c.id) 
                  or (direction in (0, 2) and c.parent_id = t.id))
select * from c

dbfiddle

根据我朝哪个方向移动,我会以不同的方式连接列表。

答案 1 :(得分:1)

由于您未提供测试数据,因此我使用了EMP表。我在EMP上创建了一个视图,以翻译为您的列名。

此解决方案从一个出发:

create or replace view v_emp(id, parent_id, name) as
select empno, mgr, ename from emp;

with target_emp as (
  select name, id, parent_id
  from v_emp 
  where name = 'JONES'
)
, descendants as (
  select connect_by_root(parent_id) id,
    substr(sys_connect_by_path(name, '/'), 2) descendant_list 
  from v_emp
  where connect_by_isleaf = 1
  start with parent_id = (select id from target_emp)
  connect by parent_id = prior id
)
, ancestors as (
  select connect_by_root(id) id,
    substr(sys_connect_by_path(name, '/'), 2) ancestor_list
  from (
    select id, name, parent_id, level lvl
    from v_emp
    start with id = (select parent_id from target_emp)
    connect by id = prior parent_id
  )
  where connect_by_isleaf = 1
  start with parent_id is null
  connect by lvl = prior lvl - 1
)
select ANCESTOR_LIST, name, DESCENDANT_LIST from target_emp
left join ancestors on 1=1
left join descendants on 1=1;

ANCESTOR_LIST   NAME    DESCENDANT_LIST   
KING            JONES   SCOTT/ADAMS        
KING            JONES   FORD/SMITH 

尝试以“ KING”,“ JONES”,“ SCOTT”然后是“ ADAMS”开头。

最诚挚的问候,

炖阿什顿

答案 2 :(得分:1)

此答案从V_EMP中的每一行开始。请注意,由于您提到了SYS_CONNECT_BY_PATH,因此我正在生成路径。如果您需要其他类型的输出,请更具体。最好的办法是使用EMP或您提供的数据显示预期的输出。

with descendants as (
  select connect_by_root(parent_id) id,
    substr(sys_connect_by_path(name, '/'), 2) descendant_list
  from v_emp
  where connect_by_isleaf = 1
  start with parent_id is not null
  connect by parent_id = prior id
)
, ancestors as (
  select root_id,
    substr(sys_connect_by_path(name, '/'), 2) ancestor_list
  from (
    select connect_by_root(id) root_id,
    id, name, parent_id, level lvl
    from v_emp
    where level > 1
    connect by id = prior parent_id
  )
  where connect_by_isleaf = 1
  start with parent_id is null
  connect by root_id = prior root_id
    and lvl = prior lvl - 1
)
select a.ancestor_list, e.name, d.descendant_list
from v_emp e
left join descendants d on e.id = d.id
left join ancestors a on e.id = a.root_id
order by a.ancestor_list nulls first, e.name, descendant_list;

ANCESTOR_LIST      NAME     DESCENDANT_LIST  
-------------      -----    ---------------
                   KING     BLAKE/ALLEN          
                   KING     BLAKE/JAMES          
                   KING     BLAKE/MARTIN         
                   KING     BLAKE/TURNER         
                   KING     BLAKE/WARD           
                   KING     CLARK/MILLER         
                   KING     JONES/FORD/SMITH     
                   KING     JONES/SCOTT/ADAMS    
KING               BLAKE    ALLEN                
KING               BLAKE    JAMES                
KING               BLAKE    MARTIN               
KING               BLAKE    TURNER               
KING               BLAKE    WARD                 
KING               CLARK    MILLER               
KING               JONES    FORD/SMITH           
KING               JONES    SCOTT/ADAMS          
KING/BLAKE         ALLEN                         
KING/BLAKE         JAMES                         
KING/BLAKE         MARTIN                        
KING/BLAKE         TURNER                        
KING/BLAKE         WARD                          
KING/CLARK         MILLER                        
KING/JONES         FORD     SMITH                
KING/JONES         SCOTT    ADAMS                
KING/JONES/FORD    SMITH                         
KING/JONES/SCOTT   ADAMS