Иерархический запрос Oracle - PullRequest
4 голосов
/ 16 ноября 2009

Использование Oracle 10g. У меня есть две таблицы:

User   Parent
-------------
1      (null)
2      1
3      1
4      3

Permission  User_ID
-------------------
A           1
B           3

Значения в таблице разрешений наследуются до потомков. Я хотел бы написать один запрос, который мог бы вернуть мне что-то вроде этого:

User    Permission
------------------
 1       A
 2       A
 3       A
 3       A
 3       B
 4       A
 4       B

Можно ли сформулировать такой запрос, используя 10g connect .. по синтаксису для извлечения строк из предыдущих уровней?

Ответы [ 4 ]

3 голосов
/ 17 ноября 2009

Вы можете достичь желаемого результата с помощью connect by (и функцией CONNECT_BY_ROOT, которая возвращает значение столбца корневого узла):

SQL> WITH users AS (
  2     SELECT 1 user_id, (null) PARENT FROM dual
  3     UNION ALL SELECT 2, 1 FROM dual
  4     UNION ALL SELECT 3, 1 FROM dual
  5     UNION ALL SELECT 4, 3 FROM dual
  6  ), permissions AS (
  7     SELECT 'A' permission, 1 user_id FROM dual
  8     UNION ALL SELECT 'B', 3 FROM dual
  9  )
 10  SELECT lpad('*', 2 * (LEVEL-1), '*')||u.user_id u,
 11         u.user_id, connect_by_root(permission) permission
 12    FROM users u
 13    LEFT JOIN permissions p ON u.user_id = p.user_id
 14  CONNECT BY u.PARENT = PRIOR u.user_id
 15   START WITH p.permission IS NOT NULL
 16  ORDER SIBLINGS BY user_id;

U         USER_ID PERMISSION
--------- ------- ----------
3               3 B
**4             4 B
1               1 A
**2             2 A
**3             3 A
****4           4 A
2 голосов
/ 17 ноября 2009

Вы можете взглянуть на http://www.adp -gmbh.ch / ora / sql / connect_by.html

1 голос
/ 17 ноября 2009

Вид черной магии, но вы можете использовать table-cast-multiset для ссылки на одну таблицу из другой в предложении WHERE:

create table t1(
  usr number,
  parent number
);

create table t2(
  usr number,
  perm char(1)
);

insert into t1 values (1,null);
insert into t1 values (2,1);
insert into t1 values (3,1);
insert into t1 values (4,3);

insert into t2 values (1,'A');
insert into t2 values (3,'B');

select t1.usr
     , t2.perm
  from t1
     , table(cast(multiset(
         select t.usr
           from t1 t
        connect by t.usr = prior t.parent
          start with t.usr = t1.usr
       ) as sys.odcinumberlist)) x
     , t2
 where t2.usr = x.column_value
;

В подзапросе x Я создаю таблицу всех родителей для данного пользователя из t1 (включая себя), затем присоединяюсь к ней с разрешениями для этих родителей.

0 голосов
/ 17 ноября 2009

Вот пример только для одного идентификатора пользователя. Вы можете использовать proc, чтобы зациклить все.

CREATE TABLE  a_lnk
(user_id VARCHAR2(5),
parent_id VARCHAR2(5));

CREATE TABLE b_perm
(perm VARCHAR2(5),
user_id VARCHAR2(5));


INSERT INTO a_lnk
   SELECT 1, NULL
     FROM DUAL;

INSERT INTO a_lnk
   SELECT 2, 1
     FROM DUAL;

INSERT INTO a_lnk
   SELECT 3, 1
     FROM DUAL;


INSERT INTO a_lnk
   SELECT 4, 3
     FROM DUAL;

INSERT INTO b_perm
   SELECT 'A', 1
     FROM DUAL;

INSERT INTO b_perm
   SELECT 'B', 3
     FROM DUAL;

-- example for just for user id = 1
--
SELECT c.user_id, c.perm
  FROM b_perm c,
       (SELECT     parent_id, user_id
              FROM a_lnk
        START WITH parent_id = 1
        CONNECT BY PRIOR user_id = parent_id
        UNION
        SELECT     parent_id, user_id
              FROM a_lnk
        START WITH parent_id IS NULL
        CONNECT BY PRIOR user_id = parent_id) d
 WHERE c.user_id = d.user_id
UNION
SELECT d.user_id, c.perm
  FROM b_perm c,
       (SELECT     parent_id, user_id
              FROM a_lnk
        START WITH parent_id = 1
        CONNECT BY PRIOR user_id = parent_id
        UNION
        SELECT     parent_id, user_id
              FROM a_lnk
        START WITH parent_id IS NULL
        CONNECT BY PRIOR user_id = parent_id) d
 WHERE c.user_id = d.parent_id;
...