递归查询以检索下面的所有子ID

时间:2019-02-02 05:36:18

标签: sql postgresql recursion

我认为我不太了解递归查询。我看到的经典递归查询是经理和员工递归查询。我正在使用该查询来捕获整个层次结构,但是我想进行查询,以使我能够捕获所有父级,子级及其级别(相对于顶层)。我感觉我需要对递归查询进行递归吗?

WITH RECURSIVE
    tree AS (
           SELECT
               id_employee,
               id_manager,
               0 AS level
           FROM
               people
           WHERE
               id_manager = '00001'--this is the boss of all bosses
           UNION ALL
           SELECT
               p.id_employee,
               p.id_manager,
               t.level + 1 AS level
           FROM
               (
               SELECT
                   id_employee,
                   id_manager
               FROM
                   people
               ) p
               JOIN tree t ON p.manager_id = t.employee_id
           )
SELECT *
FROM
    tree;

现在,由于我要担任高层领导00001,因此我将吸引组织中的所有人。但是,如果我在层次结构中间的某人的最后一行添加WHERE id_manager =子句,我将只获得他们的直接报告。我想检索该经理下的所有直接报告,还希望检索那些经理下的报告。

是否有一种方法可以修改此构建/修改此查询以维护整个层次结构,但还可以查询它以标识中间的某个人,其所有子级以及相对于顶部的相对级别级老板?

谢谢!

1 个答案:

答案 0 :(得分:1)

编辑:正如您在下面评论的那样,事实证明您的问题是我无法理解的。

您可能已经了解,递归CTE分为两部分。

WITH RECURSIVE MyCTE AS (
    <Start of the recursion/loop>
    UNION
    <Step from level N to level N+1/N-1>
)

我们将:

  1. 更改递归的起点以从正确的管理器而不是层次结构顶部的人开始。
  2. 以与您相同的方式浏览层次结构
  3. 更改循环,以便将分支扩展回顶部凸台,以正确计算级别。

Postgresql仅允许1个递归CTE(对于其他DBMS不确定),因此我们将需要一起执行2和3。我们只需要多加注意,就可以使查询以多个起点(id_manager IN (...))开头

WITH RECURSIVE tree(id_root_manager, id_direct_manager, id_employee, level) AS (
    SELECT id_manager,
           id_manager,
           id_employee,
           UNNEST(ARRAY[0,1]) /* level > 0: go to the bottom, level <= 0: go to the top of the hierarchy */
    FROM   people
    WHERE  id_manager IN ('00555')
    UNION ALL
    SELECT id_root_manager,
           id_manager,
           p.id_employee,
           CASE WHEN level <= 0 THEN level-1 ELSE level+1 END
    FROM   people p
    JOIN    tree   t ON (level > 0 AND p.id_manager = t.id_employee) OR (level <= 0 AND t.id_direct_manager = p.id_employee)
)
SELECT id_root_manager, id_direct_manager, id_employee, level - (SELECT MIN(level) FROM tree WHERE id_root_manager = h.id_root_manager) AS level
FROM tree h
WHERE level > 0
ORDER BY id_root_manager, level

如果您对“根”管理器不感兴趣,则可以通过将最终选择更改为以下方式来避免重复:

SELECT DISTINCT id_direct_manager, id_employee, level - (SELECT MIN(level) FROM tree WHERE id_root_manager = h.id_root_manager) AS level
FROM tree h
WHERE level > 0
ORDER BY level