【问题标题】:Oracle Connect By Prior for Recursive Query SyntaxOracle Connect By Prior 用于递归查询语法
【发布时间】:2013-10-24 20:59:40
【问题描述】:

假设我的 oracle DB 中有下表:

ID:    Name:     Parent_ID:
123    a         234
345    b         123
234    c         234
456    d         345
567    e         567
678    f         567

而我想做的是为每个ID 找到ULTIMATE parent ID(描述为行,当你上升时,递归地,基于Parent_ID 最终得到ID = Parent_ID 的行)。

因此,例如,345 的父级是 123,123 的父级是 234,234 的父级是 234(意味着它是链的顶部),因此 345 的最终父级是 234 - 我希望这是有道理的......

所以,我的结果应该如下所示:

ID:    Name:     Ult_Parent_ID:    Ult_Parent_Name:
123    a         234               c
345    b         234               c
234    c         234               c
456    d         234               c
567    e         567               e
678    f         567               e

我今天刚刚发现 Oracle Connect By statments,所以这对我来说是全新的,但我想我的查询必须看起来如下:

SELECT ID, Name, Parent_ID as Ult_Parent_ID, 
   (SELECT Name from MyTable t2 WHERE t2.ID = t1.Parent_ID) as Ult_Parent_Name
FROM MyTable t1
CONNECT BY PRIOR Parent_ID = ID;

现在,就像我说的,这是我第一次尝试这种 SQL - 这不起作用(我收到以下错误 [1]: ORA-01436: CONNECT BY loop in user data 并在 SQL 编辑器中突出显示表名),而且我也不知道在哪里/如何使用 START WITH 子句进行此类查询,但它的逻辑对我来说似乎是正确的。

请帮助/帮助我指出正确的方向!!!

谢谢!!!

【问题讨论】:

  • 请解释“不起作用”。您是否收到任何错误或只是错误的结果?
  • 抱歉 - 错误解释 - 我收到以下错误 [1]: ORA-01436: CONNECT BY loop in user data 并突出显示查询中的表名...抱歉...我现在也将更新 Q
  • 尝试添加NOCYCLE子句,看看你是否同意这个结果。
  • 如果您可以控制数据库内容,可能拥有 root 行,Parent_IDNULL,即没有完全是父母。
  • 感谢@PM77-1 - 是的,感谢您的提示它适用于 nocycle 子句并给了我正确的结果...我仍然不知道如何1)使其适用于所有记录(不仅适用于要检查的 1 条记录)和 2)使其在没有该条款的情况下工作。但是,是的,数据看起来是正确的。另外,不幸的是,我无法控制数据库 - 我只有查询权限...

标签: sql database oracle plsql recursive-query


【解决方案1】:

我认为 CONNECT_BY_ROOT 是您所需要的:

select x.*, t2.name ultimate_name
from
(
  select t.id, t.name, CONNECT_BY_ROOT parent_id ultimate_id
  from toto t
  start with t.id = t.parent_id
  connect by nocycle prior id = parent_id
) x, toto t2
where x.ultimate_id = t2.id
;

这给出了:

456 d   234 c
345 b   234 c
123 a   234 c
234 c   234 c
678 f   567 e
567 e   567 e

【讨论】:

  • 这成功了!!!! - 非常感谢!!! - 我自己永远不会想出这个!
【解决方案2】:

请试试这个:

SELECT ID, Name, Parent_ID as Ult_Parent_ID, 
   (SELECT Name from MyTable t2 WHERE t2.ID = t1.Parent_ID) as Ult_Parent_Name, 
   LEVEL
FROM MyTable t1
CONNECT BY NOCYCLE Parent_ID = PRIOR ID
START WITH Parent_ID = ID;

我相信我们必须使用NOCYCLE,因为你的根是如何定义的。

我添加伪列LEVEL 只是为了说明。您不必在最终查询中包含它。

SQL Fiddle 与您的测试数据

【讨论】:

  • 非常感谢您一直关注我并回答这个问题,但我仍然收到该错误 - [1]: ORA-01436: CONNECT BY loop in user data 并且它在编辑器中突出显示了表名。如果我添加NOCYCLE 子句,它就会消失......数据库是否可能被配置为不允许这个或什么???
  • 除了明显的循环 (Parent_ID = ID) 之外,您的实际数据库还可以有多行循环。像这样的两行:10, 2020,10。如果确实是后者,您将必须使用NOCYCLE 子句。
  • 我看不出如何在不更改数据的情况下避免 NOCYCLE 子句。
  • 非常感谢您的帮助和建议-我只是无法正常工作-即使使用NOCYCLE 子句...最终@Emmanuel 的解决方案证明给了我我想要的想要...
【解决方案3】:

CONNECT BY 将为您提供直接父级,但要获得最终父级,我将使用 recursive subquery。 (CONNECT_BY_ROOT 由 Emmanuel 解释也有效)

WITH r (id, parent, ultimate_parent, name, ultimate_parent_name, lvl) as
   (SELECT id, parent_id AS parent, parent_id AS ultimate_parent, name, name as ultimate_parent_name, 0 lvl
    FROM mytable
       WHERE parent_id = id -- identifies a root
UNION ALL
    SELECT m.id, r.id, ultimate_parent, m.name, r.ultimate_parent_name, r.lvl + 1
    FROM r join mytable m on m.parent_id = r.id  -- joins child with parent
    WHERE m.parent_id <> m.id -- to avoid cycles
   )
SELECT * FROM r ;

子查询的第一部分获取根,第二部分连接子查询。 Parent 是直接父级,ultimate_parent 是最终父级。

【讨论】:

  • CONNECT BY 适用于任何层次结构。它是在 Oracle 11.2 中实现递归分解子查询之前在 Oracle 中使用的。
  • 我正在尝试此查询并收到错误 [1]: ORA-00933: SQL command not properly ended 并突出显示 SELECT m.id 部分...这对您有意义吗??
  • 感谢您的帮助,但@Emmanuel 的解决方案最终证明是我想要的。谢谢!!!
【解决方案4】:

创建表test_data(order_number number(10), line_id number(10), parent_line_id number(10));

              insert into test_data values (1000, 101, 100);

              insert into test_data values (1000, 100, '');

              insert into test_data values (3000, 301, 300);

              insert into test_data values (3000, 300, '');


              select * from test_data

              select * from test_data 
              where order_number in (1000,3000) 
              start with parent_line_id is null 
              connect by prior line_id= parent_line_id

【讨论】:

    猜你喜欢
    • 2023-03-07
    • 2019-10-07
    • 2011-04-25
    • 2018-01-24
    • 2010-10-31
    • 2011-03-21
    • 1970-01-01
    • 1970-01-01
    • 2017-07-10
    相关资源
    最近更新 更多