连接具有不同行数的表而不重复

时间:2015-04-22 14:25:14

标签: sql join oracle11g union

我有一个已经很复杂的SQL语句,它创建了一个拥有权限CONNECTAPPUSER或两者的用户表:

(SELECT  b.grantee AS "Username", A.granted_role AS "Connect", b.granted_role AS "APPUSER" FROM 
    (SELECT grantee, granted_role FROM dba_role_privs WHERE granted_role = 'CONNECT')  A 
    RIGHT OUTER JOIN 
    (SELECT grantee, granted_role FROM dba_role_privs WHERE granted_role = 'APPUSER') b 
    ON A.grantee=b.grantee) 
UNION 
(SELECT  A.grantee, A.granted_role, b.granted_role FROM 
    (SELECT grantee, granted_role FROM dba_role_privs WHERE granted_role = 'CONNECT')  A 
    LEFT OUTER JOIN 
    (SELECT grantee, granted_role FROM dba_role_privs WHERE granted_role = 'APPUSER') b 
    ON A.grantee=b.grantee)

这会产生类似:

Username        Connect        APPUSER
---------      ---------      ---------
Sue             CONNECT        APPUSER
Bob             (null)         APPUSER
Joe             CONNECT        (null)

我希望使用all_users表来显示既没有权限的用户。 all_users表显示数据库中的每个用户。

我尝试在SQL语句的末尾添加几种类型的连接来实现此目的。我得到的最接近的是:

UNION
(SELECT username, NULL, NULL FROM all_users)

这将生成一个列表,其中每个用户显示两次,但显示没有正确的用户:

Username        Connect        APPUSER
---------      ---------      ---------
Amy             (null)         (null)
Sue             CONNECT        APPUSER
Sue             (null)         (null)
Bob             (null)         APPUSER
Bob             (null)         (null)
Joe             CONNECT        (null)
Joe             (null)         (null)

我尝试添加where username = a.grantee,但这对联盟不起作用。如果我尝试将UNION替换为任何JOIN,例如添加:

FULL OUTER JOIN
SELECT username, NULL, NULL FROM ALL_USERS 
on username = a.grantee;

我收到错误:

  

“SQL命令未正确结束”

3 个答案:

答案 0 :(得分:2)

您的查询似乎比必要的更复杂。这是一种方法:

select grantee,
       max(case when granted_role = 'CONNECT' then granted_role end) as "connect",
       max(case when granted_role = 'APPUSER' then granted_role end) as "appuser"
from dba_role_privs
group by grantee;

如果有用户完全没有角色,那么您将需要all_users表。

编辑:

只需使用left join

select au.userName,
       max(case when granted_role = 'CONNECT' then granted_role end) as "connect",
       max(case when granted_role = 'APPUSER' then granted_role end) as "appuser"
from all_users au join
     dba_role_privs rp
     on au.userName = rp.grantee
group by au.userName;

答案 1 :(得分:1)

我不太确定我理解第一个查询。当你可以使用PIVOT时,你似乎正在做一些非常复杂的事情。但是,如果它正常工作,那么你应该能够做到:

SELECT username 
FROM ALL_USERS 
WHERE username NOT IN (
(SELECT DISTINCT b.grantee AS "Username", A.granted_role AS "Connect", b.granted_role AS "APPUSER" FROM 
        (SELECT grantee, granted_role FROM dba_role_privs WHERE granted_role = 'CONNECT')  A 
        RIGHT OUTER JOIN 
        (SELECT grantee, granted_role FROM dba_role_privs WHERE granted_role = 'APPUSER') b 
        ON A.grantee=b.grantee) 
    UNION 
    (SELECT  A.grantee, A.granted_role, b.granted_role FROM 
        (SELECT grantee, granted_role FROM dba_role_privs WHERE granted_role = 'CONNECT')  A 
        LEFT OUTER JOIN 
        (SELECT grantee, granted_role FROM dba_role_privs WHERE granted_role = 'APPUSER') b 
        ON A.grantee=b.grantee)
)

答案 2 :(得分:1)

使用以下查询。让我知道这个是否奏效。你需要在where子句中添加dp1.granted_role为null并且dp2.granted_role为null。

select     au.username,
           dp1.granted_role,
           dp2.granted_role

    from all_users au 
    left join dba_role_privs drp1 on drp1.grantee=au.username and drp1.granted_role='CONNECT'
    left join dba_role_privs drp2 on drp2.grantee=au.username and drp2.granted_role='APPUSER'