如何根据多个属性查询行?

问题描述 投票:0回答:2

我在表用户和标签之间具有一对多关系:

Users:
id    username
--------------
 1    Bob     
 2    Alice   
 3    Eve   

Tags:
id   user_id   name
--------------------
 1   1         java         // Bobs tags...
 2   1         java script
 3   1         C#   
 4   2         java         // Alices tags...
 5   3         java         // Eves tags...
 6   3         java script

我的目标是仅提取带有标签Java或Java脚本的所有用户,而不提取具有Java,Java脚本和C#的用户。

作为查询的输出,我希望收到以下结果:

Result:
id   username
--------------
2    Alice     
3    Eve 

我曾尝试使用SQL one-to-many relationship - How to SELECT rows depending on multiple to-many properties?中的查询,但正如我注意到的,其背后的想法有点不同

sql sql-server oracle one-to-many
2个回答
0
投票

一个有效的,尽管输入很长,但选项使用exists

select u.*
from users u
where 
    not exists(select 1 from tags t where t.user_id = u.id and t.name = 'C#')
    and exists(select 1 from tags t where t.user_id = u.id and t.name = 'java ')
    and exists(select 1 from tags t where t.user_id = u.id and t.name = 'java script')

[在tags(user_id, name)上有索引,这应该非常快。


0
投票

您可以使用条件聚合逻辑来获取标签:

select t.user_id
from tags t
where t.name in ('java', 'java script', 'C#')
group by t.user_id
having sum(case when t.name = 'C#' then 1 else 0 end) = 0;   -- no C#

引入user_name只是附加联接。


0
投票

似乎HAVING可以在这里使用:

SELECT U.id,
       U.username
FROM dbo.Users U
     JOIN dbo.Tags T
GROUP BY U.ID,
         U.username
HAVING COUNT(CASE T.[name] WHEN 'java' THEN 1 END) > 0
   AND COUNT(CASE T.[name] WHEN 'java script' THEN 1 END) > 0
   AND COUNT(CASE WHEN T.[name] NOT IN ('java','java script') THEN 1 END) = 0;
© www.soinside.com 2019 - 2024. All rights reserved.