2017-10-19 106 views
0

我有一個Postgres數據庫這樣的帶桌子IDS找到所有後代遞歸CTE

id INT PRIMARY KEY, 
    value TEXT, 
    parent_id INT REFERENCES ids DEFAULT NULL 

我想找到的後代數量在此表中的所有行。因此,對於在樹子樹的大小葉子都將是1

我想用遞歸CTE做到這一點,寫了:

WITH RECURSIVE r AS (
SELECT id, parent_id 
from keyword 
where id=1 

UNION 

SELECT k.id, k.parent_id 
FROM keyword k 
join r on k.parent_id = r.id) 

select count(*) from r; 

我只可以依靠某個ID的後裔,並不適用於所有。我嘗試在CTE中按id編寫組,但它不起作用(大部分時間它都會給所有頂點的子樹大小等於1)。

基於此表,

id | parent_id | value 
----+-----------+-------- 
    1 |   | SELECT 
    2 |   1 | FROM 
    3 |   1 | WHERE 
    4 |   1 | ORDER 
    5 |   4 | BY 
    6 |   1 | GROUP 
    7 |   6 | BY 
    8 |   6 | HAVING 
11 |   | UPDATE 
12 |  11 | SET 
13 |  11 | WHERE 

我希望得到的是:

id | subtree_size 
-------+---------- 
1 | 11 
2 | 1 
6 | 3... 

而對於所有的id,它們在樹上。

+0

所有的樹:以所有根開始:'where id = 1' - >>'parent_id IS NULL'您可以在外部查詢中保留根結果和組。 – joop

+0

更正:id = 1的subtree_size爲8.({11,12,13}位於單獨的樹中) – joop

回答

1
CREATE TABLE keyword 
     (id INTEGER PRIMARY KEY 
     , parent_id INT REFERENCES keyword(id) DEFAULT NULL 
     , value TEXT 
     ); 
INSERT INTO keyword(id,parent_id, value) VALUES 
(1, NULL, 'SELECT') 
,(2, 1, 'FROM') 
,(3, 1, 'WHERE') 
,(4, 1, 'ORDER') 
,(5, 4, 'BY') 
,(6, 1, 'GROUP') 
,(7, 6, 'BY') 
,(8, 6, 'HAVING') 
,(11, NULL, 'UPDATE') 
,(12, 11, 'SET') 
,(13, 11, 'WHERE') 
     ; 


WITH RECURSIVE r AS (
     SELECT id AS root -- <<== 'Anchor' the root 
     , id, parent_id 
     from keyword 
     -- where id=1 
     -- where parent_id IS NULL 
     WHERE id IN (1,2,6) -- <<== UPDATE 
UNION 
     SELECT r.root -- <<== This is the trick: maintain the parent's root 
     , k.id, k.parent_id 
     FROM keyword k 
     join r on k.parent_id = r.id 
     ) 
select distinct k.value, r.root, count(*) AS cnt 
from r 
JOIN keyword k ON k.id = r.root 
GROUP BY r.root, k.value 
     ; 
+0

它實際上統計了整個樹中根節點的後代數量,因爲r.root始終是id根頂點。我需要遍歷所有節點並計算後代,因爲它們都是根。 –

+0

如果只有一個根,那麼顯然將只有一個組和一個聚合。 (你的問題在這方面不是很清楚) – joop

+0

對不起。我編輯了開始帖子。 –