2017-06-01 54 views
0

我有遞歸請求的問題。在我解釋之前:我使用PostgreSQL 8.4。從SQL遞歸查詢中添加額外的列

我有,概括起來講,2個表:t_object和t_package t_object有3列:ID,名稱和的package_id t_package有3列:ID,名稱和PARENT_ID (這是一個非常示意性表示這種情況。實際上是Enterprise Architect的項目數據庫)

t_package.parent_id是包的父包,你猜對了。 以遞歸方式跟蹤麪包屑時,可以獲取對象頂層包。例如:

TOPPACKAGE 
| 
+--PACKAGE 
    | 
    +--ANOTHERPACKAGE 
     | 
     +--ANOBJECT 
     +--ANOTHEROBJECT 

事情是:可以有不止一個頂包...... 我的目標是創建一個視圖,基於t_object,包含每個對象的頂級包一個額外科拉姆。

我成功ceated遞歸請求獲得一個物體的頂部封裝:

WITH RECURSIVE parents(package_id, name, parent_id) AS (
    SELECT t_package.package_id, t_package.name, t_package.parent_id 
    FROM t_package 
    WHERE t_package.package_id = (
     SELECT package_id 
     FROM t_object 
     WHERE name = 'The name of an object' 
    ) 
    UNION 
    SELECT t_package.package_id, t_package.name, t_package.parent_id 
    FROM t_package, parents 
    WHERE parents.parent_id = t_package.package_id 
) SELECT * FROM parents WHERE parent_id = 0 

於是,我試圖創建的t_object加上額外的列的觀點......沒有成功爲止!

我不得不承認,我在這裏明確地撫摸我的SQL限制,我對如何實現這一目標:(

示例數據不知道:

t_object: 
id;name;package_id 
1;'First object';11 
2;'Second object';11 
3;'Third object';14 
4;'Fourth object';12 

t_package: 
id;name;parent_id 
10;'First package';13 
11;'Second package';10 
12;'Third package';14 
13;'First root package';0 
14;'Second root package';0 

(PARENT_ID =0馬克根包)

所以層次是:

First root package 
| 
+--First Package 
    | 
    +--Second package 
     | 
     +--First object 
     +--Second object 

Second root package 
| 
+--Third object 
+--Third package 
    | 
    +--Fourth object 

我想要的結果:

t_object_with_root_package: 
id;name;package_id;root_package_id 
1;'First object';11;13 
2;'Second object';11;13 
3;'Third object';14;14 
4;'Fourth object';12;14 

感謝您的幫助

+0

編輯您的問題,並提供樣本數據和預期結果。 –

+1

Sidequestion:你確定你正在使用(非常)過時的版本8.4?而不是它最初基於它的變體之一(如紅移,greenplum等)? – pozs

+0

我完全確定該版本。這是一個純粹的Postgresql 8.4。是的,它已經過時^^ – deadbird

回答

2

這應該在8.4以及工作:

WITH RECURSIVE rcte(id, name, package_id, root_package_id) AS (
    SELECT o.id, o.name, p.id, p.id 
    FROM  t_package p 
    LEFT JOIN t_object o ON o.package_id = p.id 
    WHERE  p.parent_id = 0 
    UNION 
    SELECT o.id, o.name, c.id, p.root_package_id 
    FROM  rcte p 
    JOIN  t_package c ON c.parent_id = p.package_id 
    LEFT JOIN t_object o ON o.package_id = c.id 
) 
SELECT * 
FROM  rcte 
WHERE id IS NOT NULL 
ORDER BY id 

但現在我只能測試它在9.6: http://rextester.com/QCZPS53546

:這裏的主要想法是首先選擇根實體。然後遍歷每條路徑,直到層次結構的葉子。此外,在每個步驟中收集每個t_objectLEFT JOIN(所以rCTE輸出將包含NULL s,其中t_package沒有任何t_object)。

+0

這個完美的作品!非常感謝! – deadbird

0

這個詞的父母在你rcte是一種誤導,因爲它實際上是從下往上建立後裔的名單:

WITH RECURSIVE descendent AS (
    SELECT t_package.* FROM t_package 
    WHERE package_id in (select package_id from t_object) 
    UNION ALL 
    SELECT t_package.* FROM t_package, descendent 
    WHERE t_package.package_id = descendent.parent_id 
) 
SELECT * FROM descendent 

真的要開始在頂部和工作下來,而不是讓你可以隨身攜帶頂級父母身份證。

WITH RECURSIVE ancestry(top_id, package_id, name) AS (
    SELECT t_package.package_id as top_id 
    , t_package.package_id 
    , t_package.name 
    FROM t_package where parent_id = 0 
    UNION ALL 
    SELECT ancestry.top_id 
    , t_package.package_id 
    , t_package.name 
    FROM t_package, ancestry 
    WHERE t_package.parent_id = ancestry.package_id 
) 
SELECT * 
FROM ancestry, t_object 
WHERE ancestry.package_id=t_object.package_id 

順便說一句,使用PARENT_ID = 0,而不是空可能會比較混亂。

要允許對此字段上的package_id執行參照完整性檢查,可以插入一個包含package_id = 0的t_package行。這將成爲樹的實際根,而不是存在多個根包。