【问题标题】:Hierarchical Query: Parents parent child分层查询:parents parent child
【发布时间】:2021-10-25 23:09:15
【问题描述】:

我试图在 Oracle 中使用分层查询来实现如下所述的结果,尝试了使用 CONNECT_BY_ROOT、CONNECT BY PRIOR 的各种方法……但不知何故无法进入所需的结果。

CREATE TABLE test (
    id int, 
    name varchar2(75),
    parentid int, 
    class int
    );


INSERT into test values (1,   'BOSS',null,null);
INSERT into test values (2,   'C1',1, 0);
INSERT into test values (34,  'C2',2, 1);
INSERT into test values (37,  'C3',34, 2);
INSERT into test values (50,  'C4',37, 2);
INSERT into test values (51,  'C5',50, 4);
INSERT into test values (100, 'C6',37, 4);
INSERT into test values (101, 'C7',37, 5);

在查询中,如果我传递 'C4 的 id=50 和 class=4,那么它应该返回它的孩子,即 C5(其 parentid 为 50),同时它还应该获取 C6(因为这是 C4 的父母的孩子即 C4 的父级是 C3,它有一个子级 C6,即 parentid 37)

51  C5  50  -- This is Child of C4 i.e. C5's parent=50 
100 C6  37  -- This is because C4 parent is C3 and in turn C3 has another child C6 of same class 

我从一些基本查询开始并进行了一些更改以获取所需的结果但没有成功...我知道这是不正确的...并且遗漏了一些

SELECT distinct id, name, parentid
FROM test
CONNECT BY PRIOR id =parentid
START WITH id=50
order by 1 ;

(编辑文本)

SELECT 
distinct id, name, parentid,
    connect_by_root id          ,
    sys_connect_by_path(name,' > ') as full_path,
    CONNECT_BY_ROOT id cbr,
    CONNECT_BY_ISLEAF AS leaf    
FROM test
CONNECT BY PRIOR id =parentid
START WITH id=50
order by 1 ;

(编辑过的文字) 预期输出:

51  C5  50 
100 C6  37 

【问题讨论】:

  • 你期望的输出是什么?
  • 谢谢罗伯特,我期待下面的输出(我已经在我最初的帖子中提到了这一点,因为我的期望原因,如果你错过了任何机会:))ROW1---- 51 C5 50 ROW2---- 100 C6 37

标签: oracle


【解决方案1】:

这是一种解决方案:您需要在 connect by 子句中使用 nocycle 选项来使 oracle 在遇到循环时停止。

select distinct ID, NAME, PARENTID
from test
where class = 4
start with name = 'C4'
connect by nocycle prior id = parentid or prior parentid = parentid
order by id
;

【讨论】:

  • 非常感谢,我不确定在 CONNECT BY 子句中使用多个 PRIOR。这很有趣。
  • 是的,您可以在 CONNECT BY 子句中使用多个 PRIOR。别客气。谢谢你的提问。
  • 实际上从我上面的示例表/数据中以简化的方式呈现我的问题,但实际上我使用的查询包含视图和几个表,它获取大量记录,但最终标准是或多或少相同。我可以看到我的查询需要更多时间来执行。我只是想重构查询。但提供的线索很有用。谢谢。
【解决方案2】:

如果您想选择 id = 50 的父级的所有直接或间接子级,请使用简单的 recursive CTE

with rec_cte (ID, NAME, PARENTID, CLASS) as (
 select * from test
 where parentid = (select parentid from test where id = 50)
  union all
 select test.ID, test.NAME, test.PARENTID, test.CLASS
 from rec_cte
 join test on rec_cte.id = test.parentid
)
select * from rec_cte

按预期给出

        ID NAME    PARENTID      CLASS
---------- ----- ---------- ----------
        50 C4            37          2
       100 C6            37          4
       101 C7            37          5
        51 C5            50          4

如果您想将以上结果限制为带有class = 4 的记录,请添加过滤谓词

with rec_cte (ID, NAME, PARENTID, CLASS) as (
 select * from test
 where parentid = (select parentid from test where id = 50)
  union all
 select test.ID, test.NAME, test.PARENTID, test.CLASS
 from rec_cte
 join test on rec_cte.id = test.parentid
)
select ID, NAME, PARENTID
from rec_cte
where class = 4

这会产生您期望的结果

        ID NAME    PARENTID
---------- ----- ----------
       100 C6            37
        51 C5            50

【讨论】:

  • 非常感谢您的解决方案。我从未在 Oracle 中使用过递归 CTE,但我确实在 PostgreSQL 中使用过。非常感谢您的时间和帮助。
猜你喜欢
  • 1970-01-01
  • 2011-01-16
  • 1970-01-01
  • 2022-01-22
  • 2016-03-22
  • 1970-01-01
  • 2020-01-20
  • 1970-01-01
  • 2018-03-12
相关资源
最近更新 更多