【问题标题】:Get all of the low-level children of a node获取节点的所有低级子节点
【发布时间】:2021-11-29 06:39:27
【问题描述】:

我正在努力为 PostgreSQL 编写查询。该表类似于一棵树,每个项目都可以有 n 个子项。 我只想获取树的给定元素的最低级别的所有子节点(它们本身没有任何子节点)。

结构:

CREATE TABLE items
(
    ikey integer NOT NULL,
    description character varying(255),
    parent integer,
    CONSTRAINT i_pk PRIMARY KEY (ikey),
    CONSTRAINT i_relation FOREIGN KEY (parent)
        REFERENCES items (ikey) MATCH SIMPLE
)

表格的某些值如下所示:

 1  "Products"  NULL --Parent
 2  "Metal" 1
 3  "Nails" 2
 4  "Chains"    2
 5  "Bicycle Chains"    4
 6  "Shimano Bicycle Chains"    5
 7  "Shimano Bicycle Chains"    5
 8  "7mm chain, black"    4
 9  "Wood"  1
 10 "Cutting Boards"    8
 11 "Cutting Board Holder" 8

SO 上的大多数解决方案都处理只有 1-2 层的不太深的树。或者知道孩子需要从哪个父母那里获得。

我想选择“Chains” (4) 的所有子项,结果如下:

6   "Shimano Bicycle Chains"    5
7   "Shimano Bicycle Chains"    5
8   "7mm chain, black"    4

说实话,递归查询并不是我的强项。我已经有了颠倒搜索的想法-首先获取所有从未用作父母的项目然后再下降,但这只会将问题再次转移到我必须从给定的父母递归下降的地步,这似乎有点在顶部。

【问题讨论】:

  • 我不明白你是想要所有的孩子,还是只想要叶子的孩子。似乎应该包括“10 - 切菜板”,但它不在您的列表中。

标签: sql postgresql


【解决方案1】:

如果您想在所有级别中查找某个项目的所有子项,您可以编写递归 CTE。例如:

with recursive
n as (
  select * from items where parent = 4 -- Children of "Chains"
 union all
  select i.*
  from n
  join items i on i.parent = n.ikey
)
select * from n

结果:

 ikey  description               parent 
 ----- ------------------------- ------ 
 5     Bicycle Chains            4      
 8     7mm Chain Black           4      
 6     Shimano Bicycle Chains 1  5      
 7     Shimano Bicycle Chains 2  5      

请参阅DB Fiddle 的运行示例。

【讨论】:

    【解决方案2】:

    您不需要递归查询。相反,您可以简单地选择带有ikeys 且不作为父级出现的行:

    select i1.* from items i join items i1 on i.ikey = i1.parent where i.parent = 4 and 
        not exists (select 1 from items i2 where i2.parent = i1.ikey)
    

    【讨论】:

    • 在我的数据集一遍又一遍地运行它之后,在我看来,这只会返回没有任何孩子的下一个较低级别的父级
    【解决方案3】:

    另一个递归 CTE,带有附加功能。
    启动树的递归和级别的基本键。

    WITH RECURSIVE RCTE_OFFSPRING AS (
      SELECT ikey as base, 0 as lvl
      , ikey, description, parent
      FROM items
      WHERE ikey = 4
      
      UNION ALL
      
      SELECT cte.base, cte.lvl + 1
      , itm.ikey, itm.description, itm.parent
      FROM items itm
      JOIN RCTE_OFFSPRING cte 
        ON cte.ikey = itm.parent
    )
    SELECT * 
    FROM RCTE_OFFSPRING
    WHERE lvl > 0
    ORDER BY base, lvl, ikey
    
    base lvl ikey description parent
    4 1 5 Bicycle Chains 4
    4 1 8 7mm chain, black 4
    4 2 6 Shimano Bicycle Chains 5
    4 2 7 Shimano Bicycle Chains 5

    db小提琴here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-12
      • 1970-01-01
      • 1970-01-01
      • 2019-02-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多