如果您使用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
您可以只需添加另一種添加addtional角色來此查詢柱。例如,查看此查詢:
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
感謝這麼多的翔實的答案! :) – user3236074
再次你好!我查看了你給我的信息,我不確定這是我要找的。我們使用的客戶端是10g,所以我們不能使用PIVOT。與此同時,我並不想將行變成列,而是使用類似於SQL中的excell VLOOKUP公式的東西。 *繼續* – user3236074
我想在第一列中有select * from特權,第二列爲特定角色返回數據(例如,調查員)以及是否具有特定的權限。換句話說,如果ROLE_PRIV中有一個指示說明角色具有來自第一列的特定權限,並且在一個步驟中基本上爲每個特權重複此操作,則返回yes。因此,最終結果將是PRIVILEGES列(包含所有priv)和包含YES/NO的列調查器,指示調查員是否擁有權限。 – user3236074