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

dgiusagp  于 2021-07-26  发布在  Java
关注(0)|答案(3)|浏览(332)

我在表user和tag之间有一对多关系:

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一对多关系-如何根据多对多属性选择行?但我注意到它背后有点不同的想法

v7pvogib

v7pvogib1#

一个有效的,虽然很长的类型,选项使用 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) ,这应该很快。

pxy2qtax

pxy2qtax2#

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

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 只是一个附加连接。

o0lyfsai

o0lyfsai3#

看起来像是 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;

你也可以替换前两个 HAVING 包含以下内容的条款:

COUNT(DISTINCT CASE WHEN T.[name] IN ('java','java script') THEN T.[name] END) = 2

相关问题