jab*_*245 13 sql postgresql tree recursive-query common-table-expression
使用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);
Run Code Online (Sandbox Code Playgroud)
id | name | parent_id
----+--------------+-----------
1 | parent |
2 | child | 1
3 | grandchild A | 2
4 | grandchild B | 2
Run Code Online (Sandbox Code Playgroud)
我想为这些单元创建一个访问控制列表,其中每个单元可能拥有自己的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);
Run Code Online (Sandbox Code Playgroud)
unit_id
---------
1
4
Run Code Online (Sandbox Code Playgroud)
我正在使用一个视图来确定一个单元是否从祖先继承它的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;
Run Code Online (Sandbox Code Playgroud)
unit_id | inheriting
---------+------------
1 | f
2 | t
3 | t
4 | f
Run Code Online (Sandbox Code Playgroud)
我的问题是:我怎样才能得到最近的单元,它不是从祖先继承ACL?我的预期结果应类似于下表/视图:
unit_id | acl
---------+------------
1 | 1
2 | 1
3 | 1
4 | 4
Run Code Online (Sandbox Code Playgroud)
Erw*_*ter 13
使用递归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
Run Code Online (Sandbox Code Playgroud)
第二站的休息状态UNION
是n.acl IS NULL
.这样,一旦acl
找到,查询就会停止遍历树.
在最后,SELECT
我们只返回找到的行acl
.瞧.
暂且不说:使用通用的非描述性id
列名作为反模式.可悲的是,默认情况下,一些ORM会这样做.调用它unit_id
,您不必一直在查询中使用别名.
归档时间: |
|
查看次数: |
6820 次 |
最近记录: |