我有以下表格:ROLE,PRIVILEGE和ROLE_PRIV。每个角色和每个权限都有唯一的ID和名称,而ROLE_PRIV包含两个表之间的链接,表示每个角色的权限(每个角色ID +私有ID组合都是唯一的)。
我正在尝试生成一个报告,其中我将拥有一个包含所有权限的列,顶行列出所有角色ID,然后在下面的单元格中显示YES / NO,指示此角色是否具有指定的特定权限。
我非常感谢任何能够就我是否可以创建查询或PL / SQL程序来设置此报告的指导。我也很好,只获得一个角色的信息,因为它们通常不超过10次,重复查询/程序10次对我来说不会有问题。
我对SQL有很好的经验,对PL / SQL的经验很少,但是如果给出好的指示就足以修补一些东西。
感谢您花时间阅读本文。 :)
答案 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