找到递归CTE的所有后代

时间:2017-10-19 08:58:43

标签: postgresql recursion common-table-expression

我有一个这样的postgres数据库,表格为 ids

  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;

我只能计算某些身份的后代,而不是所有人。我试图在CTE中写入id by group,但它不起作用(大多数时候它给所有顶点的子树大小等于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。

1 个答案:

答案 0 :(得分: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
        ;