PostgreSQL-经理层次结构的递归CTE自加入

时间:2019-02-02 06:17:50

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

我无法在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 |                                                           |
+------------+-------------+-----------------------------------------------------------+

在我的数据集,可能有N个级别从任何给定员工的CEO了,所以递归我必须结束后每一位员工已经达到了CEO,谁还会有manager_employee_id NULL值。

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

1 个答案:

答案 0 :(得分:0)

我将其视为递归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是db <>小提琴。