2009-11-16 2 views
4

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

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 

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

ответ

3

вы можете достичь желаемого результата с помощью подключения (и функции 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 
+0

+1 Не знаю, о connect_by_root. Моя версия работает в 9i, но ваш путь лучше. –

0

Вот пример только для одного идентификатора пользователя. вы можете использовать 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; 
1

Вид черной магии, но вы можете использовать настольный монолитно-MultiSet ссылаться одну таблицу из другой в ИНЕКЕ:

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 (включая его), затем присоедините его к разрешениям для этих родителей.

Смежные вопросы