私は現在、企業のユーザー管理をリエンジニアリングしており、5つのデータベースインスタンスすべてのすべてのユーザーをリストするテーブルを作成しています。次のステップは、すべてのインスタンスに対してユーザーが持つすべての役割を示すクエリを記述する必要があることです。
私はすでに_UNION ALL
_を使用しましたが、出力は構造化されておらず、どのインスタンスでどのロールを使用しているかはわかりません。だから私はたった3つのテーブルで以下を試しました:
_SELECT W.GRANTED_ROLE "GRANTED_ROLE_DB1", V.GRANTED_ROLE "GRANTED_ROLE_DB2"
FROM SCHEMA.USR_ALL_USERS U
LEFT OUTER JOIN SYS.DBA_ROLE_PRIVS W
ON (U.USERNAME = W.GRANTEE AND U.DB_INSTANCE = 'DB1')
LEFT OUTER JOIN SYS.DBA_ROLE_PRIVS@DB2_LINK V
ON (U.USERNAME = V.GRANTEE AND U.DB_INSTANCE = 'DB2')
WHERE U.USERNAME = 'USER'
ORDER BY U.USERNAME ASC;
_
実際には機能しましたが、出力は満足のいくものではありませんでした:
_GRANTED_ROLE_DB1 GRANTED_ROLE_DB2
--------------------------- --------------------------
ROLE_1
ROLE_2
ROLE_3
ROLE_4
ROLE_1
ROLE_2
ROLE_4
ROLE_5
ROLE_6
_
このような出力をする方法はありますか?
_GRANTED_ROLE_DB1 GRANTED_ROLE_DB2
--------------------------- --------------------------
ROLE_1 ROLE_1
ROLE_2 ROLE_2
ROLE_3
ROLE_4 ROLE_4
ROLE_5
ROLE_6
_
私はON ((U.USERNAME = V.GRANTEE OR W.GRANTED_ROLE = V.GRANTED_ROLE) AND U.DB_INSTANCE = 'DB2')
を試しましたが、出力はさらに悪かったです。
あなたたちは何か提案や役立つ考えがありますか?
SCHEMA.USR_ALL_USERS
テーブルは実際にこのクエリに参加する必要がありますか?それはそうではないようです:結果をフィルタリングしている同じ列USERNAME
は、他の2つのテーブルを結合するためにも使用されます。したがって、SCHEMA.USR_ALL_USERS
を省略して、SYS.DBA_ROLE_PRIVS
とSYS.DBA_ROLE_PRIVS@DB2_LINK
に直接フィルタリングを適用できます。
そして今、これらの2つのテーブルの2つのサブセットがあるので、 @ Chris Saxon's アプローチを取り、FULL JOINを使用することができます。
SELECT
DB1.GRANTED_ROLE AS "GRANTED_ROLE_DB1",
DB2.GRANTED_ROLE AS "GRANTED_ROLE_DB2"
FROM (
SELECT GRANTED_ROLE
FROM SYS.DBA_ROLE_PRIVS
WHERE GRANTEE = 'USER'
) DB1
FULL OUTER JOIN (
SELECT GRANTED_ROLE
FROM SYS.DBA_ROLE_PRIVS@DB2_LINK
WHERE GRANTEE = 'USER'
) DB2
ON DB1.GRANTED_ROLE = DB2.GRANTED_ROLE
ORDER BY
COALESCE(DB1.GRANTED_ROLE, DB2.GRANTED_ROLE)
;
または、2つのセットを結合することもできます。
SELECT
'GRANTED_ROLE_DB1' AS GRANTED_ROLE_DB,
GRANTED_ROLE
FROM SYS.DBA_ROLE_PRIVS
WHERE GRANTEE = 'USER'
UNION ALL
SELECT
'GRANTED_ROLE_DB2' AS GRANTED_ROLE_DB,
GRANTED_ROLE
FROM SYS.DBA_ROLE_PRIVS@DB2_LINK
WHERE GRANTEE = 'USER'
このような結果を得る:
GRANTED_ROLE_DB GRANTED_ROLE
---------------- ------------
GRANTED_ROLE_DB1 ROLE_1
GRANTED_ROLE_DB1 ROLE_2
GRANTED_ROLE_DB1 ROLE_3
GRANTED_ROLE_DB1 ROLE_4
GRANTED_ROLE_DB2 ROLE_1
GRANTED_ROLE_DB2 ROLE_2
GRANTED_ROLE_DB2 ROLE_4
GRANTED_ROLE_DB2 ROLE_5
GRANTED_ROLE_DB2 ROLE_6
次にPIVOTします。このような:
SELECT
CASE WHEN "'GRANTED_ROLE_DB1'" > 0 THEN GRANTED_ROLE END AS GRANTED_ROLE_DB1,
CASE WHEN "'GRANTED_ROLE_DB2'" > 0 THEN GRANTED_ROLE END AS GRANTED_ROLE_DB2
FROM (
SELECT
'GRANTED_ROLE_DB1' AS GRANTED_ROLE_DB,
GRANTED_ROLE
FROM SYS.DBA_ROLE_PRIVS
WHERE GRANTEE = 'USER'
UNION ALL
SELECT
'GRANTED_ROLE_DB2' AS GRANTED_ROLE_DB,
GRANTED_ROLE
FROM SYS.DBA_ROLE_PRIVS@DB2_LINK
WHERE GRANTEE = 'USER'
) s
PIVOT (
COUNT(*) FOR GRANTED_ROLE_DB IN ('GRANTED_ROLE_DB1', 'GRANTED_ROLE_DB2')
) p
ORDER BY
GRANTED_ROLE
;
「動作中」の両方のアプローチを見ることができます SQL Fiddle 。
問題は、インスタンスフィールドを制限しているため、ロールが一方または他方の列にしか表示されないことです。
これを回避するには、次のように、2番目のデータベースから最初のデータベースの役割へのdb_instance
およびfull outer join
役割の制限を削除します。
SELECT W.GRANTED_ROLE "GRANTED_ROLE_DB1", V.GRANTED_ROLE "GRANTED_ROLE_DB2"
FROM SCHEMA.USR_ALL_USERS U
LEFT OUTER JOIN SYS.DBA_ROLE_PRIVS W
ON (U.USERNAME = W.GRANTEE)
FULL OUTER JOIN SYS.DBA_ROLE_PRIVS@DB2_LINK V
ON (U.USERNAME = V.GRANTEE AND V.GRANTED_ROLE = W.GRANTED_ROLE)
WHERE nvl(U.USERNAME, v.username) = 'USER'
ORDER BY nvl(W.GRANTED_ROLE, V.GRANTED_ROLE) ASC;