2016-06-30 4 views
1

を根絶するまで横断し、要素の許可を探すには、私がのPostgreSQL:ここ

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の許可が必要な場合は、私が直接許可テーブルを照会して取得することができているを使用しているDBの構造であります読み取り/書き込み/削除の値。 しかし、私は4の許可をしたい場合、それは許可テーブルに存在しないので、私は2の許可を持っているので、私は2を返すことができるので、2、 の親を見つける必要があります。

私は3の許可が必要な場合、私は許可テーブルで確認し、それが存在しない、それは(0-ある親のため が行く、存在しない親(1)、を参照 、よりトリッキーRoot)を返し、値を返します。

これはどのレベルでも構いませんが、私たちは許可テーブルのレコード2,5,6を持っていないと想像してください。 したがって、私が6を検索するときには、アクセス権を取得するためにすべての方法でトラバースする必要があります。

注:私たちは常にルートの許可を得ています。

これは、アプリケーションレイヤーよりもDBレイヤーで実行したいので、SQLクエリー(再帰型)やストアードプロシージャーの作成に役立つでしょう。

ありがとうございます!

+0

そして、現時点では 'ltype'フィールドは無視できますか? – joop

+0

@joop、私たちが無視することができる瞬間ですが、私の実際の解決策では親としてリンクタイプだけを見つける必要があります。 – rtv

答えて

2

あなたはこのためRECURSIVE CTEを使用することができます。Permissionレコードがデータベースから取得されたとき

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は終了します。

Demo here

+0

@Giorog Betsos、ありがとう!!しかし、ID = 3では動作しませんが、レコードは返されませんが、期待される動作は0の許可を返すことです。 – rtv

+0

@rtvなぜあなたは間違った答えを受け入れますか? – joop

+0

@joop、それは解決するかどうかを確認するか、少なくとも解決の方法を見つけるので、私たちはほぼ解決策に近いようにチェックしました。おそらく私は今のところそれをチェックしないようにすることができます。 – rtv

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 
     ; 

結果:FYI

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) 

:ここではあまりエレガントでtreewalkアップが、ある、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 
     ; 
+0

ありがとう!!あなたのソリューションは横断しますが、私はそれを必要とします。意味は0を与えればすべての要素が表示され、2を与えると2の子が最後のノードまで表示されます – rtv

+0

これは実装上の問題ですので、上に行く必要はありません。 item = xのパーミッションが必要です。 – joop

+0

完璧!ありがとう!!私はちょうどどこに条件を追加し、希望のアイテムの許可を得ることができました。 – rtv

関連する問題