4

使用 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

4 回答 4

2

你可以看看http://www.adp-gmbh.ch/ora/sql/connect_by.html

于 2009-11-16T21:22:17.933 回答
2

CONNECT_BY_ROOT您可以通过 connect by (以及返回根节点的列值的函数)来实现所需的结果:

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
于 2009-11-17T14:10:48.363 回答
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,然后将其加入到这些父级的权限中。

于 2009-11-16T21:53:12.963 回答
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;
于 2009-11-16T21:44:14.040 回答