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

Joining tables with different number of rows without duplicates

我有一个已经很复杂的 SQL 语句创建了 table 个拥有 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_userstable,来显示没有这两种权利的用户。all_userstable 显示数据库中的每个用户。

我已经尝试在 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,但这不适用于联合会。如果我尝试用任何 JOIN 替换 UNION,例如添加:

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

我收到错误:

"SQL command not properly ended"

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

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 table。

编辑:

只需使用 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;

我不太确定我理解第一个查询。当您可以使用 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)
)

使用以下查询。让我知道这个是否奏效。您需要在 where 子句中添加 dp1.granted_role is null and dp2.granted_role is 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'