2017-10-19 108 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

对不起。我编辑了开始帖子。 –