SQL过程返回一个表的所有值,如果存在,则返回YES / NO

时间:2014-02-10 08:52:11

标签: sql plsql

我有以下表格:ROLE,PRIVILEGE和ROLE_PRIV。每个角色和每个权限都有唯一的ID和名称,而ROLE_PRIV包含两个表之间的链接,表示每个角色的权限(每个角色ID +私有ID组合都是唯一的)。

我正在尝试生成一个报告,其中我将拥有一个包含所有权限的列,顶行列出所有角色ID,然后在下面的单元格中显示YES / NO,指示此角色是否具有指定的特定权限。

我非常感谢任何能够就我是否可以创建查询或PL / SQL程序来设置此报告的指导。我也很好,只获得一个角色的信息,因为它们通常不超过10次,重复查询/程序10次对我来说不会有问题。

我对SQL有很好的经验,对PL / SQL的经验很少,但是如果给出好的指示就足以修补一些东西。

感谢您花时间阅读本文。 :)

1 个答案:

答案 0 :(得分:2)

如果您使用的是11g或更高版本的Oracle,则将行转换为列的最简单方法是PIVOT运算符(documentation)。例如,考虑这个查询 - 它将为您提供所有角色和特权的表格,并为其提供相应的值:

SELECT * FROM
(SELECT fj.role_name, fj.priv_name, DECODE(rp.val,1,'YES',0,'NO','-') VAL
FROM (SELECT r.id role_id, r.name role_name, p.id priv_id, p.name priv_name
      FROM ROLE r, PRIVILEGE p) fj
      LEFT JOIN ROLE_PRIV rp ON fj.role_id = rp.role_id AND fj.priv_id = rp.priv_id)
PIVOT (MAX(VAL) FOR PRIV_NAME IN (list_of_privileges))
ORDER BY ROLE_NAME

但是有这样一个解决方案:你需要在IN子句中命名每个特权(或者使用XML关键字,但它会弄乱结果),但是,考虑到那些应该不经常改变的特权列表,这应该不是问题。以下示例:

WITH ROLE AS (SELECT 1 ID, 'ROLE1' NAME FROM DUAL
              UNION
              SELECT 2 ID, 'ROLE2' NAME FROM DUAL
              UNION
              SELECT 3 ID, 'ROLE3' NAME FROM DUAL),
     PRIVILEGE AS (SELECT 1 ID, 'READ' NAME FROM DUAL
                   UNION
                   SELECT 2 ID, 'WRITE' NAME FROM DUAL
                   UNION
                   SELECT 3 ID, 'EXECUTE' NAME FROM DUAL),
     ROLE_PRIV AS (SELECT 1 ROLE_ID, 1 PRIV_ID, 1 VAL FROM DUAL
                   UNION
                   SELECT 1 ROLE_ID, 2 PRIV_ID, 0 VAL FROM DUAL
                   UNION
                   SELECT 2 ROLE_ID, 1 PRIV_ID, 1 VAL FROM DUAL
                   UNION
                   SELECT 2 ROLE_ID, 2 PRIV_ID, 0 VAL FROM DUAL
                   UNION
                   SELECT 3 ROLE_ID, 1 PRIV_ID, 0 VAL FROM DUAL
                   UNION
                   SELECT 3 ROLE_ID, 3 PRIV_ID, 1 VAL FROM DUAL)
SELECT * FROM
(SELECT fj.role_name, fj.priv_name, DECODE(rp.val,1,'YES',0,'NO','-') VAL
FROM (SELECT r.id role_id, r.name role_name, p.id priv_id, p.name priv_name
      FROM ROLE r, PRIVILEGE p) fj
      LEFT JOIN ROLE_PRIV rp ON fj.role_id = rp.role_id AND fj.priv_id = rp.priv_id)
PIVOT (MAX(VAL) FOR PRIV_NAME IN ('READ','WRITE','EXECUTE'))
ORDER BY ROLE_NAME

会给你以下结果:

ROLE_NAME   'READ'  'WRITE' 'EXECUTE'
ROLE1   YES NO  -
ROLE2   YES NO  -
ROLE3   NO  -   YES

如果您使用的是早期版本的Oracle,则可以考虑其他解决方案(like this one)。


好吧,如果你不能使用PIVOT操作,获得所需输出的最简单方法就是这个查询:

SELECT p.name, DECODE((SELECT VAL 
                       FROM ROLE_PRIV rp
                       WHERE rp.role_id = (SELECT ID 
                                           FROM ROLE r
                                           WHERE r.name = :ROLE_NAME)
                             AND rp.priv_id = p.id),
                       1, 'YES',
                       0, 'NO',
                       '-') :ROLE_NAME
FROM PRIVILEGE p

只需添加其他列,即可为此查询添加地址角色。例如,看一下这个查询:

WITH ROLE AS (SELECT 1 ID, 'ROLE1' NAME FROM DUAL
              UNION
              SELECT 2 ID, 'ROLE2' NAME FROM DUAL
              UNION
              SELECT 3 ID, 'ROLE3' NAME FROM DUAL),
     PRIVILEGE AS (SELECT 1 ID, 'READ' NAME FROM DUAL
                   UNION
                   SELECT 2 ID, 'WRITE' NAME FROM DUAL
                   UNION
                   SELECT 3 ID, 'EXECUTE' NAME FROM DUAL),
     ROLE_PRIV AS (SELECT 1 ROLE_ID, 1 PRIV_ID, 1 VAL FROM DUAL
                   UNION
                   SELECT 1 ROLE_ID, 2 PRIV_ID, 0 VAL FROM DUAL
                   UNION
                   SELECT 2 ROLE_ID, 1 PRIV_ID, 1 VAL FROM DUAL
                   UNION
                   SELECT 2 ROLE_ID, 2 PRIV_ID, 1 VAL FROM DUAL
                   UNION
                   SELECT 3 ROLE_ID, 1 PRIV_ID, 0 VAL FROM DUAL
                   UNION
                   SELECT 3 ROLE_ID, 3 PRIV_ID, 1 VAL FROM DUAL)
SELECT p.name, 
       DECODE((SELECT VAL 
               FROM ROLE_PRIV rp
               WHERE rp.role_id = (SELECT ID 
                                   FROM ROLE r
                                   WHERE r.name = 'ROLE1')
                     AND rp.priv_id = p.id),
              1, 'YES',
              0, 'NO',
              '-') ROLE1,
       DECODE((SELECT VAL 
               FROM ROLE_PRIV rp
               WHERE rp.role_id = (SELECT ID 
                                   FROM ROLE r
                                   WHERE r.name = 'ROLE2')
                     AND rp.priv_id = p.id),
              1, 'YES',
              0, 'NO',
              '-') ROLE2,
       DECODE((SELECT VAL 
               FROM ROLE_PRIV rp
               WHERE rp.role_id = (SELECT ID 
                                   FROM ROLE r
                                   WHERE r.name = 'ROLE3')
                     AND rp.priv_id = p.id),
              1, 'YES',
              0, 'NO',
              '-') ROLE3
FROM PRIVILEGE p

它将为您提供三种角色的结果。


这样的事情应该有效:

SELECT p.name, 
       DECODE((SELECT COUNT(1)
               FROM ROLE_PRIV rp
               WHERE rp.role_id = (SELECT ID 
                                   FROM ROLE r
                                   WHERE r.name = 'ROLE1')
                     AND rp.priv_id = p.id),
              0, 'NO',
              'YES') ROLE1
FROM PRIVILEGE p