如何在 Oracle SQL 中检索父行的所有递归子代?

Posted

技术标签:

【中文标题】如何在 Oracle SQL 中检索父行的所有递归子代?【英文标题】:How to retrieve all recursive children of parent row in Oracle SQL? 【发布时间】:2013-06-25 20:06:04 【问题描述】:

我有一个递归查询,它确实扩展了这个 Java 猴子的 SQL 知识的极限。现在终于凌晨 1:30,可能是时候开始寻求帮助了。这是 Google 让我失望的少数几次之一。

表格如下:

Parent_ID CHILD_ID QTY
25        26        1
25        27        2
26        28        1
26        29        1
26        30        2
27        31        1
27        32        1
27        33        2

我正在尝试获得以下结果,其中父母将每个孩子都列在他们的下方。请注意,数量的级联也是如此。

BASE    PARENT_ID  CHILD_ID   QTY
25         25        26        1
25         25        27        2
25         26        28        1
25         26        29        1
25         26        30        1
25         27        31        2
25         27        32        2
25         27        33        4
26         26        28        1
26         26        29        1
26         26        30        2
27         27        31        1
27         27        32        1
27         27        33        2

我尝试了以下几种偏差都无济于事。

SELECT *
FROM MD_BOMS
START WITH PARENT_ID is not null
CONNECT BY PRIOR CHILD_ID = PARENT_ID
ORDER BY PARENT_ID, CHILD_ID

我正在使用 Oracle 数据库。任何建议、想法等将不胜感激。这似乎很接近,但我不确定它是否是我正在寻找的:Retrieve all Children and their Children, recursive SQL

基于(Retrieve all Children and their Children, recursive SQL)我也尝试了以下方法,但收到“ WITH 子句中查询名称的非法引用”错误:

with cte as (
    select  CHILD_ID, PARENT_ID, CHILD_ID as head
    from    MD_BOMS
    where   PARENT_ID is not null
    union all
    select  ch.CHILD_ID, ch.PARENT_ID, p.head
    from    MD_BOMS ch
    join    cte pa
    on      pa.CHILD_ID = ch.PARENT_ID
)
select  *
from    cte

【问题讨论】:

我不明白,数量必须如何计算。请解释一下。 嗨奥拉夫。这种特殊的结构对物料清单 (BOM) 进行建模。这是一种描述哪些组件构成其他组件的方式。不足之处在于分量 qtys 是乘法的。例如,如果 25 中有 2 个 27,那么 25 中就会有 4 个 31。回想起来,我在原来的帖子中确实打错了字。 25 中应该只有 1 30。 【参考方案1】:

你很接近:

select connect_by_root parent_id base, parent_id, child_id, qty
from md_boms
connect by prior child_id = parent_id
order by base, parent_id, child_id;

          BASE  PARENT_ID   CHILD_ID        QTY
    ---------- ---------- ---------- ----------
            25         25         26          1 
            25         25         27          2 
            25         26         28          1 
            25         26         29          1 
            25         26         30          2 
            25         27         31          1 
            25         27         32          1 
            25         27         33          2 
            26         26         28          1 
            26         26         29          1 
            26         26         30          2 
            27         27         31          1 
            27         27         32          1 
            27         27         33          2 

     14 rows selected 

connect_by_root operator 为您提供基础parent_id

SQL Fiddle.

我不确定您是如何计算您的 qty 的。我猜你想要通往孩子的道路的总数,但这与你所展示的不符。然后,作为起点,非常大量借鉴this answer,您可以尝试以下操作:

with hierarchy as (
  select connect_by_root parent_id base, parent_id, child_id, qty,
    sys_connect_by_path(child_id, '/') as path
  from md_boms
  connect by prior child_id = parent_id
)
select h.base, h.parent_id, h.child_id, sum(e.qty)
from hierarchy h
join hierarchy e on h.path like e.path ||'%'
group by h.base, h.parent_id, h.child_id
order by h.base, h.parent_id, h.child_id;

     BASE  PARENT_ID   CHILD_ID SUM(E.QTY)
---------- ---------- ---------- ----------
        25         25         26          1 
        25         25         27          2 
        25         26         28          2 
        25         26         29          2 
        25         26         30          3 
        25         27         31          3 
        25         27         32          3 
        25         27         33          4 
        26         26         28          1 
        26         26         29          1 
        26         26         30          2 
        27         27         31          1 
        27         27         32          1 
        27         27         33          2 

 14 rows selected 

【讨论】:

亚历克斯,谢谢!当我接受 ThinkJet 的回答时,这就是我所寻找的一切。如果我可以投票给你,我会的。 同意@WillLovett :-)【参考方案2】:

@AlexPoole 的答案很棒,我只是想用更直观的查询变体来扩展他的答案,以沿路径求和值。 此变体基于recursive subquery factoring 功能,在Oracle 11g R2 中引入。

with recursion_view(base, parent_id, child_id, qty) as (
   -- first step, get rows to start with
   select 
     parent_id base, 
     parent_id, 
     child_id, 
     qty
  from 
    md_boms

  union all

  -- subsequent steps
  select
    -- retain base value from previous level
    previous_level.base,
    -- get information from current level
    current_level.parent_id,
    current_level.child_id,
    -- accumulate sum 
    (previous_level.qty + current_level.qty) as qty 
  from
    recursion_view previous_level,
    md_boms        current_level
  where
    current_level.parent_id = previous_level.child_id

)
select 
  base, parent_id, child_id, qty
from 
  recursion_view
order by 
  base, parent_id, child_id

SQLFiddle example(用一个数据行扩展以演示超过 2 个级别的工作)

【讨论】:

ThinkJet,这很好用!在我从 10g 升级到 11g R2 之后,我所要做的就是复制和粘贴,它就像一个魅力。我唯一改变的是用乘法代替加法,这给了我正确的数量。我对你和亚历克斯的回答都感到非常惊讶。这对我有很大帮助! 关于更多问题是否可以...当我尝试将您的查询转换为视图时,我收到 SQL Parse Exception: Error(s) parsing SQL: syntax error near ! 如下:with !*recursion_view(base, parent_id, child_id, qty) as ( *! 附近有语法错误: with recursion_view*!*(base, parent_id, child_id,数量)作为( @WillLovett - 错误中的!* 来自哪里?您可以通过在其前面粘贴create view my_view as 将其转换为视图,并且不更改任何其他内容。如果您正在做其他事情,您可能需要提出一个新问题,显示您在问题中使用的确切代码。 @AlexPoole 我发布了两张截图:williverstravels.com/JDev/Forums/***/17358109/… 和williverstravels.com/JDev/Forums/***/17358109/… 第一张带有 ! * 是当我使用 JDeveloper 11g 时,使用 Database Navigator,右键单击 View 并选择“New View”。单击“确定”时收到错误消息。我确实可以通过 sql 脚本创建视图,但是当我尝试查看数据时,我收到 ORA_00600 错误。 在花了 6 个小时之后,我决定不使用 JDev 的图形编辑器,而简单地写 SELECT * FROM BOMS_VIEW;它就像一个魅力。我只是不能使用数据选项卡在编辑器中查看记录。希望我在 5 小时前就知道了。

以上是关于如何在 Oracle SQL 中检索父行的所有递归子代?的主要内容,如果未能解决你的问题,请参考以下文章

HTML:如何使用 AngularJs 填充第一行是父行和后续行是子行的行

●oracle——层次化查询

如何从 qtreeview 中的父行中获取特定列

父行的颤振列自动高度

每个父行的随机基数

SQL如何从每个连接表中检索最新结果