2009-11-16 114 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(包括其本身)的给定用户,然后以这些父母的权限加入它。