我有3张这样的桌子:
User:
Id | Name
Role:
Id | Name
User2Role:
RoleId | UserId | RoleName
有没有一种方法可以选择在没有子查询的查询中具有RoleName'A'和('B'xor'C')的用户,因此仅AB或AC,而不仅仅是BC而不是A等。
到目前为止,我只能想到这一点:
select U.Name, R.Name
from User2Role UR join User U on UR.UserId = U.Id
join Role R on UR.RoleId = R.Id
where R.Name = 'A'
添加多个EXISTS,将其变成丑陋的混乱。 但是还有更优雅的解决方案吗?
答案 0 :(得分:1)
您可以尝试以下操作:
with role_abc as (
select
u.id, u.name,
max(decode(r.name, 'A', 1, 0)) as has_a,
max(decode(r.name, 'B', 1, 0)) as has_b,
max(decode(r.name, 'C', 1, 0)) as has_c
from usr u
inner join user2role ur on ur.userid = u.id
inner join role r on r.id = ur.roleid
group by u.id, u.name
)
select id, name from role_abc
where has_a = 1 and has_b + has_c = 1
条件非常简洁明了-以with子句的价格为准。
如果还需要角色名称,则可以轻松加入他们。
由于在oracle上进行了测试,因此不得不将表用户的名称缩写为usr。
答案 1 :(得分:0)
您可以使用having
子句。假设角色没有重复:
select ur.userid
from user2role ur join
roles r
on ur.roleid = r.id
where r.name in ('A', 'B', 'C')
group by ur.userid
having sum(case when r.name = 'A' then 1 else 0 end) > 0 and
count(*) = 2; -- two matches overall
更明确的having
子句为:
having sum(case when r.name = 'A' then 1 else 0 end) = 1 and
sum(case when r.name in ('B', 'C') then 1 else 0 end) = 1