2017-03-21 84 views
1

我有一個包含父/子關係的數據庫,並且我試圖摺疊數據以便子標識在同一行中具有其所有父標識。遞歸連接PostgreSQL從子標識查找所有父標識

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; 

回答

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