树结构和递归

Posted

技术标签:

【中文标题】树结构和递归【英文标题】:Tree Structure and Recursion 【发布时间】:2012-10-22 11:15:11 【问题描述】:

使用 PostgreSQL 8.4.14 数据库,我有一个表示树结构的表,如下例所示:

CREATE TABLE unit (
    id bigint NOT NULL PRIMARY KEY,
    name varchar(64) NOT NULL,
    parent_id bigint,
    FOREIGN KEY (parent_id) REFERENCES unit (id)
);
INSERT INTO unit VALUES (1, 'parent', NULL), (2, 'child', 1)
                      , (3, 'grandchild A', 2), (4, 'grandchild B', 2);
 id |    name      | parent_id 
----+--------------+-----------
  1 | parent       |          
  2 | child        |         1
  3 | grandchild A |         2
  4 | grandchild B |         2

我想为这些单元创建一个访问控制列表,其中每个单元可能有它自己的 ACL,或者从最近的祖先那里继承它并拥有自己的 ACL。

CREATE TABLE acl (
    unit_id bigint NOT NULL PRIMARY KEY,
    FOREIGN KEY (unit_id) REFERENCES unit (id)
);
INSERT INTO acl VALUES (1), (4);
 unit_id 
---------
       1
       4

我正在使用视图来确定一个单元是否从祖先那里继承了它的 ACL:

CREATE VIEW inheriting_acl AS
    SELECT u.id AS unit_id, COUNT(a.*) = 0 AS inheriting
    FROM unit AS u
    LEFT JOIN acl AS a ON a.unit_id = u.id
    GROUP BY u.id;
 unit_id | inheriting 
---------+------------
       1 | f
       2 | t
       3 | t
       4 | f

我的问题是:我怎样才能得到最近的单位,即从祖先那里继承 ACL?我的预期结果应该类似于下表/视图:

 unit_id | acl 
---------+------------
       1 | 1
       2 | 1
       3 | 1
       4 | 4

【问题讨论】:

+1 非常好的问题。 总是,应该包含您的 PostgreSQL 版本。 【参考方案1】:

带有recursive CTE 的查询可以完成这项工作。需要 PostgreSQL 8.4 或更高版本:

WITH RECURSIVE next_in_line AS (
    SELECT u.id AS unit_id, u.parent_id, a.unit_id AS acl
    FROM   unit u
    LEFT   JOIN acl a ON a.unit_id = u.id

    UNION  ALL
    SELECT n.unit_id, u.parent_id, a.unit_id
    FROM   next_in_line n
    JOIN   unit u ON u.id = n.parent_id AND n.acl IS NULL
    LEFT   JOIN acl a ON a.unit_id = u.id
    )
SELECT unit_id, acl
FROM   next_in_line
WHERE  acl IS NOT NULL
ORDER  BY unit_id

UNION 第二段的中断条件是n.acl IS NULL。这样,一旦找到acl,查询就会停止遍历树。 在最终的SELECT 中,我们只返回找到acl 的行。瞧。

顺便说一句:使用通用的、非描述性的id 作为列名是一种反模式。可悲的是,一些 ORM 默认情况下会这样做。称它为unit_id,您不必一直在查询中使用别名。

【讨论】:

以上是关于树结构和递归的主要内容,如果未能解决你的问题,请参考以下文章

第04次作业-树

[数据结构] 树森林的遍历

js递归树结构

CTE递归获取树层次结构

数据结构--Avl树的创建,插入的递归版本和非递归版本,删除等操作

数据结构 - 二叉树遍历(递归,非递归)与构造