递归连接PostgreSQL从子ID中查找所有父ID

时间:2017-03-21 21:52:40

标签: sql postgresql recursive-query

我有一个包含父/子关系的数据库,我试图折叠数据,以便子ID的所有父ID都在同一行。

Name | ID | Parent_ID
A         1       NULL
B         2       1
C         3       2
D         4       3

我正在尝试实现以下目标:

Name | ID | Top_Level   | Sub_Level | Sub_Level_2
A         1       NULL
B         2         1
C         3         1     2
D         4         1     2            3

我玩了一些递归,但没有得到正确的结果,我不知道如何继续。任何提示将不胜感激!

with recursive stuff as (

  select
    *
  from table
  where
    id = 4
  union
  select
    table.*
  from table
  join stuff on stuff.parent_id = table.id
)
select * from stuff;

1 个答案:

答案 0 :(得分:0)

不是很优雅,但我现在想不出任何不同的东西:

with recursive stuff (name, id, parent_id, nodes, level) as (
  select name, id, parent_id, array[parent_id], 1 as level
  from t
  where id = 4
  union
  select c.name, c.id, c.parent_id, p.nodes||c.parent_id, p.level + 1
  from t c
    join stuff p on p.parent_id = c.id
), level_info as (
  select max(level) as max_level
  from stuff
), path_info as (
  select nodes as all_nodes
  from stuff
  where level = (select max_level from level_info)
)
select stuff.name, 
       stuff.id,
       stuff.level, 
       case 
         when level = max_level then null
         else all_nodes[max_level - 1]
       end as root,
       case 
         when level < max_level - 1 then all_nodes[max_level - 2] 
       end as sub_level,
       case 
         when level < max_level - 2 then all_nodes[max_level - 3] 
       end as sub_level_2
from stuff, path_info, level_info
order by id;

递归部分收集访问的每个节点的整个路径。然后我们需要计算最长路径和最高等级,以便能够找到最高等级和两个子等级。这就是其他两个CTE所做的事情。

我将它们交叉连接到基础CTE,以便能够访问那里的列。由于两个CTE只有一行,因此交叉连接不会更改结果,但可以更轻松地使用这些值。

尽管如此,这可能不是最有效的方式。

在线示例:http://rextester.com/KVOG87512