SQL选择作为交集而不是一个联合

[英]SQL select where in as intersection instead of a union


I'll explain the problem with examples so it is easy to understand, given the following data structure:

我将用一些例子来解释这个问题,以便于理解,考虑到以下数据结构:

id  userId  
1   1    
1   2    
2   2    
3   2    
1   3     
2   3 

I can get a list of ids for a set of users as follows:

我可以得到一组用户的id列表如下:

declare @tmp table (id int, userId int)
insert into @tmp values(1,1), (1,2), (2,2), (3,2), (1,3), (2,3)


select id from @tmp
where userId in (1,2,3)
group by id

This will return the following as expected:

这将按预期返回以下内容:

id
1
2
3

My question is, how can I only get the ids that have mapping for EVERY userId in the where clause? e.g. the result for userId in (1,2,3) should be 1 and for userId in (2,3) should be 1,2

我的问题是,如何才能获得where子句中的每个userId的映射?例如,(1,2,3)中的userId应该是1,(2,3)中的userId应该是1,2

I've tried going through each id and then merging those but so far had no luck on finding an actual solution.

我尝试过遍历每个id然后合并它们,但是到目前为止还没有找到一个真正的解决方案。

NOTE The solution must work for larger data sets, imagine millions of rows and thousands of userIds, efficiency of the solution is not as important (as it does not have to run very often)

注意,解决方案必须适用于更大的数据集,设想有数百万行和数千个用户id,解决方案的效率并不那么重要(因为它不必经常运行)

Second NOTE I just noticed that counting the result does not actually guarantee correctness, because two different userIds may have the same count of mappings but mapped to different Items. In that scenario it is not an intersection anymore

第二,我刚刚注意到计算结果并不能保证正确性,因为两个不同的userIds可能具有相同的映射计数,但映射到不同的项。在那种情况下,它不再是一个交集

5 个解决方案

#1


1  

You could use a count of user IDs to check... Like this

您可以使用用户id计数来检查……像这样

SELECT Id
From table
Where userid in (1,2,3)
Group by id
Having count(userid) = (select count(distinct userid) from table where userid in(1,2,3))

Ideally the 2 conditions get parameterized, but that is outside the scope of this question.

理想情况下,这两个条件被参数化,但这不在问题的范围之内。

#2


1  

I have used temp table to store userids

我使用了临时表来存储用户名

declare @tmp table (id int, userId int)
insert into @tmp values(1,1), (1,2), (2,2), (3,2), (1,3), (2,3)

declare @userid table (id int)
insert into @userid values (1), (2), (3)

select
    t.id
from 
    (select *, cnt = count(*) over () from @userid) u
    join @tmp t on u.id = t.userId
group by t.id, u.cnt
having u.cnt = count(distinct u.id)

#3


1  

You can avoid a count distinct as well as having to enter your userId values more than once - or at all if you populate the equivalent of the @i dataset from a dynamic query:

您可以避免一个计数的不同,并且必须多次输入您的userId值——或者,如果您从一个动态查询中填充了与@i数据集相等的值,那么您就可以这样做:

declare @t table (id int, userId int);
insert into @t values(1,1), (1,2), (2,2), (3,2), (1,3), (2,3);

declare @i table (i int);
insert into @i values(1),(2),(3);

select t.id
from @i as i
    join @t as t
        on i.i = t.userId
group by t.id
having count(i.i) = (select count(1) from @i);

#4


1  

If your only problem is that you want to specify the user IDs just once, use your user table:

如果您唯一的问题是您只想指定一次用户id,请使用您的用户表:

with u as (select userid from users where userid in (1,2,3))
select id 
from mytable
where userid in (select userid from u)
group by id
having count(distinct userid) = (select count(*) from u);

If you wanted to react on invalid user IDs with an empty result set, you'd replace the users table with a values clause:

如果您想用一个空的结果集对无效的用户id进行响应,您可以用values子句替换users表:

with u as (select userid from (values (1), (2), (3)) AS ids(userid))

#5


0  

One method is using HAVING:

一种方法是使用拥有:

SELECT id
FROM YourTable
GROUP BY id
HAVING COUNT(CASE WHEN UserID = 1 THEN 1 END) > 0
   AND COUNT(CASE WHEN UserID = 2 THEN 1 END) > 0
   AND COUNT(CASE WHEN UserID = 3 THEN 1 END) > 0;
关注微信公众号

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2018/02/21/7defd52aeff444d2e28ece161fb7339a.html



 
粤ICP备14056181号  © 2014-2020 ITdaan.com