Oracle分层查询

时间:2009-11-16 20:37:54

标签: sql oracle oracle10g hierarchy

使用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 .. by语法来制定这样的查询以从以前的级别中提取行?

4 个答案:

答案 0 :(得分:3)

你可以通过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

答案 1 :(得分:2)

答案 2 :(得分:1)

一种黑魔法,但您可以使用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(包括其自身)的给定用户的所有父项的表,然后使用这些父项的权限加入它。

答案 3 :(得分: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;