【问题标题】:How does one print depth-level in a Postgres query that uses RECURSIVE to select descendants?如何在使用 RECURSIVE 选择后代的 Postgres 查询中打印深度级别?
【发布时间】:2016-03-01 16:29:45
【问题描述】:

我有一个表persons,其中包含parent_id 的列,它引用同一个表中的另一行。假设这是逻辑层次结构:

          P1
  P2      P3      P4
P5  P6  P7  P8  P9  P10

我写了一个查询,打印给定节点的所有父节点,以及节点上方的高度,它似乎工作正常:

WITH
RECURSIVE ancestors AS (
  SELECT id, parent_id
    FROM persons
    WHERE id = 8
  UNION
    SELECT p.id, p.parent_id
      FROM persons p
      INNER JOIN ancestors
        ON
          p.id = ancestors.parent_id
  )
SELECT persons.id, persons.name,
      ROW_NUMBER() over () as height
  FROM ancestors
  INNER JOIN persons
  ON
    ancestors.id = persons.id
  WHERE
    persons.id <> 8

结果:

  id   |    name     | height 
-------+-------------+---------
    3  | P3          |      1
    1  | P1          |      2
(2 rows)

我现在想编写一个类似地打印所有后代以及深度的查询。这是目前的查询(与上面相同,idparent_id 在 UNION 连接中交换):

WITH
RECURSIVE descendants AS (
  SELECT id, parent_id
    FROM persons
    WHERE id = 1
  UNION
    SELECT p.id, p.parent_id
      FROM persons p
      INNER JOIN descendants
        ON
          p.parent_id = descendants.id
  )
SELECT persons.id, persons.name,
      ROW_NUMBER() over () as depth
  FROM descendants
  INNER JOIN persons
  ON
    descendants.id = persons.id
  WHERE
    persons.id <> 1

这给出了以下结果:

  id   |    name     | depth
-------+-------------+---------
    2  | P2          |      1
    3  | P3          |      2
    4  | P4          |      3
    5  | P5          |      4
    6  | P6          |      5
    7  | P7          |      6
    8  | P8          |      7
    9  | P9          |      8
    10 | P10         |      9
(9 rows)

显然,深度是错误的。 ROW_NUMBER() 没有做我想做的事。我该怎么办?

我曾考虑在查询本身的递归部分中使用计数器,每次运行时都会递增,但我不确定是否有办法实现。

【问题讨论】:

    标签: postgresql recursion tree recursive-query depth


    【解决方案1】:

    使用一个额外的整数列,其值在每个递归步骤中递增。

    WITH RECURSIVE descendants AS (
        SELECT id, parent_id, 0 AS depth
        FROM persons
        WHERE id = 1
    UNION
        SELECT p.id, p.parent_id, d.depth+ 1
        FROM persons p
        INNER JOIN descendants d
        ON p.parent_id = d.id
    )
    SELECT p.id, p.name, depth
    FROM descendants d
    INNER JOIN persons p
    ON d.id = p.id
    WHERE p.id <> 1;
    
     id | name | depth 
    ----+------+-------
      2 | P2   |     1
      3 | P3   |     1
      4 | P4   |     1
      5 | P5   |     2
      6 | P6   |     2
      7 | P7   |     2
      8 | P8   |     2
      9 | P9   |     2
     10 | P10  |     2
    (9 rows)
    

    Db<>fiddle.

    【讨论】:

      猜你喜欢
      • 2021-03-27
      • 2022-10-15
      • 2011-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-25
      • 2020-07-25
      • 1970-01-01
      相关资源
      最近更新 更多