簡體   English   中英

樹結構和遞歸

[英]Tree Structure and Recursion

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

使用遞歸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的中斷條件是n.acl IS NULL 這樣,一旦找到acl ,查詢就會停止遍歷樹。
在最后的SELECT我們只返回找到acl的行。 瞧。

旁白:使用通用的非描述性id作為列名是一種反模式。 可悲的是,默認情況下,一些ORM會這樣做。 將其unit_id ,您不必一直在查詢中使用別名。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM