2009-11-16 78 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 

是否有可能採用了10G連接。通過語法從以前的水平行拉來制定這樣的查詢?

回答

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,但你的方式更好。 – 2009-11-17 19:31:12

0

下面是隻有一個用戶ID的例子。你可以使用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

的魔法種類,但你可以使用表鑄多重集從另一個引用一個表中的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(包括其本身)的給定用戶,然後以這些父母的權限加入它。