【问题标题】:Recursive query to retrieve all child ids below递归查询以检索下面的所有子 ID
【发布时间】:2019-02-03 08:07:56
【问题描述】:

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

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 = 子句,我只会得到他们的直接下属。我想检索该经理下方的所有直接下属,以及这些经理下方的报告。

有没有办法修改此构建/修改此查询以维护上面的整个层次结构,但也能够查询它以识别其中的某个人、他们的所有孩子以及他们与顶部的相对级别级boss?

谢谢!

【问题讨论】:

  • 如果我添加WHERE id_manager= 是什么意思?如果您替换您当前的WHERE id_manager = '00001' --this is the boss of all bosses 由您想要的经理,那还不够吗? ?
  • @lau - 抱歉,我不清楚。我的意思是我想将WHERE id_manager= 添加到查询的最后一行。现在,如果我这样做,我只会得到00555 的直接下属,而不是那些下属的下属。理想情况下,递归查询应该为每个父母的每个孩子返回多条记录。
  • 就像提示一样——在 manager Id 字段上添加一个聚集索引(您可能必须删除并重新创建主键字段才能执行此操作)。这将使父子查询速度至少提高一个数量级。

标签: sql postgresql recursion


【解决方案1】:

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

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

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

我们会:

  1. 将递归的起点更改为从正确的经理开始,而不是从层次结构顶部的人开始。
  2. 以与您相同的方式浏览层次结构
  3. 为了正确计算关卡,更改循环以将分支延伸回顶部 Boss。

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

【讨论】:

  • 我想我理解你在做什么,但是使用这种方法,级别重置为 0。如果 00555 是整个树中的级别 5,则此查询会将他设置为级别 0。我仍然想检索 00555 及其子级,相对于整个树的顶层。
猜你喜欢
  • 1970-01-01
  • 2011-03-18
  • 1970-01-01
  • 1970-01-01
  • 2017-10-27
  • 1970-01-01
  • 2013-02-10
  • 2011-02-01
  • 1970-01-01
相关资源
最近更新 更多