以下是使用
的数据库结构Item
----
ID [PK]
Name
Desc
Links
-----
ID [FK]
LID [FK] -- Link ID
LType -- Link Type (Parent, Alias)
Permission
----------
ID [FK]
CanRead
CanWrite
CanDelete
Let's assume, we have the below data in the table
Item Table
-----------
ID Name Desc
=================
0 Root Base Item
1 One First
2 Two Second
3 Three Third
4 Four Forth
5 Five Fifth
6 Six Sixth
Links Table
-----------
ID LID LType
==================
1 0 Parent
2 0 Parent
3 1 Parent
4 2 Parent
5 4 Parent
6 5 Parent
0
|- 1
| |- 3
|- 2
|- 4
|- 5
|- 6
Permission Table
-----------------
ID CanRead CanWrite CanDelete
=====================================
0 T T T
2 T F F
5 T T F
6 F F F
问题是,如果我想要6的权限,我可以直接查询Permission表并获取Read / Write / Delete值。 但是,如果我想要4的权限,它在权限表中不存在,所以我需要找到父,即2, 因为我有2个人的许可,所以我可以退货。
更棘手, 如果我想要3的权限,我签入权限表,它不存在,请参阅不存在的父(1), 去它的父母是(0-Root),然后返回值。
这可以适用于任何级别,假设我们在权限表中没有记录2,5,6, 所以当我查找6时,我需要一直遍历到root以获得权限。
注意:我们始终拥有Root的权限。
我希望在数据库层而不是应用程序层完成此任务,因此编写SQL查询(递归)或存储过程的任何帮助都会很棒。
谢谢!
答案 0 :(得分:2)
您可以使用RECURSIVE CTE
:
WITH RECURSIVE Perms(ID, Name, ParentID, CanRead, CanWrite, CanDelete) AS (
SELECT i.ID, i.Name, l.LID AS ParentID, p.CanRead, p.CanWrite, p.CanDelete
FROM Item AS i
LEFT JOIN Permission AS p ON i.ID = p.ID
LEFT JOIN Links AS l ON i.ID = l.ID
), GET_PERMS(ID, ParentID, CanRead, CanWrite, CanDelete) AS (
-- Anchor member: Try to get Read/Write/Delete values from Permission table
SELECT ID, ParentID, CanRead, CanWrite, CanDelete
FROM Perms
WHERE ID = 3
UNION ALL
-- Recursive member: terminate if the previous level yielded a `NOT NULL` result
SELECT p.ID, p.ParentID, p.CanRead, p.CanWrite, p.CanDelete
FROM GET_PERMS AS gp
INNER JOIN Perms AS p ON gp.ParentID = p.ID
WHERE gp.CanRead IS NULL
)
SELECT CanRead, CanWrite, CanDelete
FROM GET_PERMS
WHERE CanRead IS NOT NULL
从数据库中检索到RECURSIVE CTE
记录时Permission
终止。
答案 1 :(得分:1)
WITH RECURSIVE tree AS (
SELECT i.id AS my_id
, p.id AS perm_id
FROM items i
JOIN permission p ON p.id = i.id
WHERE i.id = 0 -- root
UNION ALL
SELECT l.id AS my_id
, COALESCE (p.id,t.perm_id) AS perm_id
FROM links l
JOIN tree t ON l.lid = t.my_id
LEFT JOIN permission p ON p.id = l.id
)
SELECT i.*, t.perm_id
, p.canread, p.canwrite, p.candelete
FROM items i
JOIN tree t ON t.my_id = i.id
JOIN permission p ON t.perm_id = p.id
;
结果:
CREATE TABLE
CREATE TABLE
CREATE TABLE
INSERT 0 7
INSERT 0 6
INSERT 0 4
id | name | descr | perm_id | canread | canwrite | candelete
----+-------+-----------+---------+---------+----------+-----------
0 | Root | Base Item | 0 | t | t | t
1 | One | First | 0 | t | t | t
2 | Two | Second | 2 | t | f | f
3 | Three | Third | 0 | t | t | t
4 | Four | Forth | 2 | t | f | f
5 | Five | Fifth | 5 | t | t | f
6 | Six | Sixth | 6 | f | f | f
(7 rows)
仅供参考:这是树木行走,不太优雅,IMO
WITH RECURSIVE tree_up AS (
SELECT i.id AS my_id
, p.id AS perm_id
FROM items i
LEFT JOIN permission p ON p.id = i.id
WHERE i.id = 3 -- << PARAMETER: starting point
UNION ALL
SELECT l.lid AS my_id
, COALESCE (t.perm_id,p.id) AS perm_id
FROM tree_up t
JOIN links l ON l.id = t.my_id
LEFT JOIN permission p ON p.id = l.lid
WHERE t.perm_id IS NULL
)
SELECT i.*, t.perm_id
, p.canread, p.canwrite, p.candelete
FROM items i
JOIN tree_up t ON t.my_id = i.id
JOIN permission p ON t.perm_id = p.id
;