Получите доступ из таблиц с родством родитель-потомок - PullRequest
0 голосов
/ 05 августа 2020

У меня есть следующая схема для хранения иерархии узлов и доступа к узлу для роли. Роль наследует доступ к дочерним узлам из набора доступа к родительскому узлу, если у него нет записи в таблице accessdetails.

Я хочу получить потомков, уровень и доступ для конкретного узла для данной роли. В этом случае роль равна 1, а родительскому - 'b'.

SQLfiddle ссылка

CREATE TABLE hierarchy
    (parent varchar(1), node varchar(1))
;

CREATE TABLE accessdetails
    (role integer, node varchar(1), access integer)
;
    
INSERT INTO hierarchy
    (parent, node)
VALUES
    (NULL, 'a'),
    ('a', 'b'),
    ('b', 'c'),
    ('c', 'p'),
    ('p', 'q'),
    ('q', 'r'),
    ('b', 'd'),
    ('d', 'j'),
    ('a', 'e'),
    ('e', 'f'),
    ('f', 'x')
;

/*
0-no,1-r,2-w,3-full
*/

insert into accessdetails
  (role, node, access)
values
  (1, 'b', 3),
  (1, 'c', 2),
  (1, 'p', 0)
 ;

Следующий запрос возвращает уровень и потомков правильно, но я не могу получить правильный доступ.

with recursive
descendants as
  ( select parent, node as descendant, 1 as level,
     (select access from accessdetails where node=hierarchy.node and role=1) as access
    from hierarchy where parent = 'b'
  union all
    select d.parent, s.node, d.level + 1, 
   (select access from accessdetails where node=s.node and role=1) as access
    from descendants as d
      join hierarchy s
        on d.descendant = s.parent
  ) 
select descendant, level, access 
from descendants
order by parent, level, descendant ;
Current output:
descendant  level   access
c           1   2
d           1   (null)
j           2   (null)
p           2   0
q           3   (null)
r           4   (null)
Expected output:
descendant  level   access
c           1   2
d           1   3
j           2   3
p           2   0
q           3   0
r           4   0

Как мне этого добиться?

Окончательное решение с небольшими изменениями в схеме:

1 Ответ

1 голос
/ 05 августа 2020

Проблема здесь в том, что вы начинаете свою иерархию с узлов, имеющих b в качестве родителя. Это узлы c и d. Узел c имеет явно назначенный доступ 2, а узел d - нет. Запрос не «видит» доступ 3, назначенный узлу b, потому что эта строка не включена в запрос.

Этот запрос - это то, как я подхожу к проблеме. Он генерирует всю иерархию, а затем ограничивает ее строками, которые имеют b в качестве первого узла на своем пути.

Fiddle Here

with recursive descendants as ( 
  select h.parent, h.node as descendant, 1 as level, ad.access,
         array[h.node]::text[] as path
    from hierarchy h
         left join accessdetails ad on ad.node = h.node
  union all
    select d.parent, s.node, d.level + 1, 
           coalesce(ad.access, d.access), d.path||s.node::text
      from descendants as d
           join hierarchy s
             on d.descendant = s.parent
           left join accessdetails ad on ad.node = s.node
  ) 
select descendant, level, access, path
  from descendants
 where path[1] = 'b'
 order by parent, level, descendant ;
...