我正在尝试获取ID列表的所有后代。 就像目录树一样,其中ID列表是具有访问权限的目录,包括子目录。要导航到文件夹,我还需要提升。
我尝试了UNION提升者和后代,但是如果这样做,我将没有正确的SYS_CONNECT_BY_PATH结果,因为提升者是颠倒的。
我的表有一个ID,名称和Parent_ID。
是否有机会进行这项工作?
答案 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
根据我朝哪个方向移动,我会以不同的方式连接列表。
答案 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