2015-09-26 109 views
0

我有一些數據,看起來像這樣:在層次結構遞歸查詢和同行

CREATE TABLE relations (
    group_member_id int not null, 
    group_boss_id int not null); 

INSERT INTO relations (group_member_id, group_boss_id) 
VALUES (19, 21), (21, 21), (19, 20), (20, 20), (21, 22), (22, 22); 

的基本思路是,一組成員可能在各種不同的老闆各種不同羣體(如19是兩組,分別帶有凸臺21和20)。小組成員可能是他自己的老闆(例如,20是20的老闆)。

隱含地,如果這些成員共享相同的老闆,則組成員與另一組成員在同一組中。因此,19和21在同一組中,因爲他們共享21作爲老闆,19和20在同一組中,因爲他們共享20作爲老闆,並且21和22在同一組中,因爲他們共享22作爲老闆。

對於每個組成員,我想找到最大老闆ID,不僅老闆標識明確地聯繫到該組成員,但依賴於該成員的其他隱性組成員的所有老闆的ID,和他們的小組會員等。我想要達到的最終輸出是:

group_member_id | largest_boss_id 
     19   22 
     20   22 
     21   22 
     22   22 

我已經試過了編碼這種非遞歸沒有多少運氣:我在的主要問題是以下20至21之間的關係,然後從21到22,並在每一步收集同齡組成員。

+0

既然你正在尋找的「最大老闆ID」,做思想有一定的意義呢?特別是,'group_member_id <= group_boss_id'總是正確的?此外,由於您正在使用臨時表,您是否可以發佈此信息的來源 - 在該結構上可能會有更高效的解決方案。 – Patrick

+0

@Patrick是的,group_member_id將始終爲<= group_boss_id。我正在咀嚼的實際問題是重複數據刪除問題:每個「group_member_id」是某行的ID,「largest_boss_id」是該行的暫定重複數據刪除版本的ID。我真的試圖確定行19,20,21和22都是同一行的真正副本,因此應該全部映射到第22行,因爲它們全都在同一鏈中鏈接到「老闆」 22. –

回答

2

如果它不是用於同等成員資格問題(即成員#20通過具有成員#19作爲對等成員而具有最優秀的老闆#22),這將是相當容易的查詢。

簡單的部分是遞歸查詢membership,它建立所有直接關係,包括通過多層次的層次結構。然而,20號會員本身就是超級老闆,因爲沒有考慮到同伴關係。

UNION中添加了所有同行的超級上司,其中有來自membership CTE的行。對於每個成員查找此成員是其中的其他成員(WHERE篩選器中的子SELECT),然後找到所有這些成員的超級老闆,並與當前成員配對。 (是的,不容易解釋...)。由於查詢使用簡單的UNION(而不是UNION ALL),所有重複項都被刪除。

最後,在主查詢中,選擇(成員,uber boss)對。

SELECT group_member_id, max(group_boss_id) AS uber_boss 
FROM (
    -- Recursive query identifies all direct relationships 
    WITH RECURSIVE membership AS (
    SELECT group_member_id, group_boss_id FROM relations 
    UNION 
    SELECT m.group_member_id, r.group_boss_id 
    FROM membership m 
    JOIN relations r ON r.group_member_id = m.group_boss_id 
) 
    SELECT * FROM membership 

    UNION 

    -- Now need to find all uber bosses of peers 
    SELECT m.group_member_id, uber_boss 
    FROM membership m, 
    LATERAL (
    SELECT group_member_id, max(group_boss_id) AS uber_boss 
    FROM membership 
    WHERE group_member_id IN (
     -- The below selects the peers 
     SELECT group_member_id FROM membership WHERE group_boss_id = m.group_member_id) 
    GROUP BY 1 
    ) chief 

) qry 
GROUP BY group_member_id 
ORDER BY group_member_id; 

SQLFiddle

+0

這是**真棒**非常感謝你(以及編輯幫助)。我仍在消化代碼和解釋,但它似乎給了我完全的東西。 –