gpt4 book ai didi

sql - 树结构和递归

转载 作者:行者123 更新时间:2023-11-29 11:13:17 24 4
gpt4 key购买 nike

使用 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

我正在使用一个 View 来确定一个单元是否从祖先那里继承了它的 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 的单元?我的预期结果应类似于下表/ View :

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

最佳答案

带有 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,您就不必一直在查询中使用别名。

关于sql - 树结构和递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13184334/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com