【问题标题】:PostgreSQL - Recursive CTE Self-Join for Manager HierarchyPostgreSQL - 用于管理器层次结构的递归 CTE 自联接
【发布时间】:2019-02-02 06:17:49
【问题描述】:

我在 PostgreSQL 中组合一个递归查询以显示员工之间的管理层次结构时遇到了麻烦。为了实现这一点,我需要将表自我连接到自身,直到每个员工都到达其层次结构的末尾。我的数据在某一天看起来像这样:

+------------+-------------+-----------------+---------------------+
|    date    | employee_id | terminated_flag | manager_employee_id |
+------------+-------------+-----------------+---------------------+
| 2019-01-31 |           3 |               0 |                   2 |
| 2019-01-31 |           2 |               1 |                   1 |
| 2019-01-31 |           1 |               0 |                     |
+------------+-------------+-----------------+---------------------+

理想情况下,我想创建一个 JSONB 列,其中包含给定员工的完整层次结构和经理详细信息。我知道我可以通过递归附加到现有的 JSONB 列,但要达到这一点一直很困难。所需的输出将如下所示(删除列以便于阅读):

+------------+-------------+-----------------------------------------------------------+
|    date    | employee_id |                     manager_hierarchy                     |
+------------+-------------+-----------------------------------------------------------+
| 2019-01-31 |           3 | {{"level":1,"id":2,"term":1},{"level":2,"id":1,"term":0}} |
| 2019-01-31 |           2 | {{"level":1,"id":1,"term":0}}                             |
| 2019-01-31 |           1 |                                                           |
+------------+-------------+-----------------------------------------------------------+

在我的数据集中,从任何给定的员工到 CEO 之间可能存在 N 个级别,因此,一旦每个员工到达 CEO,递归就需要结束,而 CEO 的 manager_employee_id 的值为 NULL。

这可能吗?感谢您的帮助!

【问题讨论】:

    标签: sql postgresql common-table-expression recursive-query


    【解决方案1】:

    我会将此视为递归 CTE 以获取层次结构,然后聚合以创建 jsonb 值:

    with recursive t as (
          select v.*
          from (values (3, 2, 0), (2, 1, 1), (1, null, 0)) v(employee_id, manager_employee_id, terminated_flag)
         ),
         cte as (
          select distinct employee_id, manager_employee_id, terminated_flag, 1 as lev
          from t
          union all
          select cte.employee_id, t.manager_employee_id, t.terminated_flag, lev + 1
          from cte join
               t
               on cte.manager_employee_id = t.employee_id
         )
    select employee_id, jsonb_agg(jsonb_build_object('level', lev, 'id', manager_employee_id, 'terminated_flag', terminated_flag))
    from cte
    group by employee_id;
    

    Here 是一个 dbfiddle。

    【讨论】:

      猜你喜欢
      • 2023-03-24
      • 2013-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-23
      • 1970-01-01
      • 2013-11-22
      相关资源
      最近更新 更多