递归获取Postgres表中树的根ID

Bog*_*dan 1 sql postgresql recursive-query common-table-expression hierarchical-data

我有一个Postgres表users(E_8_User),其中包含User_id作为主键,Boss作为同一个表的外键(它不可为空,如果某些用户没有boss,则其Boss属性= user_id)。我需要为表中的所有用户获取他们的老板,所以我尝试编写 CTE 查询:

WITH RECURSIVE herarchy_reports AS (
    SELECT E_8_User.User_id, E_8_User.Boss, 1 as lvl, E_8_User.User_id as RootUserID
    FROM E_8_User
    WHERE E_8_User.User_id=E_8_User.Boss
    UNION ALL
    SELECT usr.User_id, usr.Boss, lvl+1 as lvl, rep.RootUserID
    FROM herarchy_reports as rep JOIN E_8_User as usr ON
    rep.user_id=usr.Boss
)
SELECT * FROM herarchy_reports ORDER BY RootUserID;
Run Code Online (Sandbox Code Playgroud)

但它不起作用:数据库不断执行查询。我究竟做错了什么?

GMB*_*GMB 5

这是一个典型的递归查询:

with recursive cte as (
    select u.user_id, u.boss, 1 as lvl from e_8_user u
    union all
    select u.user_id, c.boss, lvl + 1
    from cte c 
    inner join e_8_user u on u.boss = c.user_id and u.user_id != c.user_id
)
select user_id, boss 
from cte c
where lvl = (select max(c1.lvl) from cte c1 where c1.user_id = c.user_id) 
order by user_id
Run Code Online (Sandbox Code Playgroud)

在递归查询中,技巧是当记录与其自身连接(u.boss = c.user_id and u.user_id != c.user_id)时停止递归。

然后,在外部查询中,您要选择每个用户具有最高级别的记录。

假设以下样本数据:

用户 ID | 老板
------: | ---:
      1 | 1
      2 | 1
      3 | 2
      4 | 3
      5 | 2
      6 | 6
      7 | 6

查询产生:

用户 ID | 老板
------: | ---:
      1 | 1
      2 | 1
      3 | 1
      4 | 1
      5 | 1
      6 | 6
      7 | 6

DB Fiddle 上的演示

在 Postgres 中,我们可以使用以下方法简化外部查询distinct on

with recursive cte as (
    select u.user_id, u.boss, 1 as lvl from e_8_user u
    union all
    select u.user_id, c.boss, lvl + 1
    from cte c 
    inner join e_8_user u on u.boss = c.user_id and u.user_id != c.user_id
)
select distinct on (user_id) user_id, boss 
from cte c
order by user_id, lvl desc
Run Code Online (Sandbox Code Playgroud)

演示