简体   繁体   English

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 id s 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? 我的问题是,我怎么只在where子句中获得具有每个 userId映射的ID? eg the result for userId in (1,2,3) should be 1 and for userId in (2,3) should be 1,2 例如userId in (1,2,3)的结果应为1 userId in (2,3)应为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,然后合并这些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) 注意该解决方案必须适用于较大的数据集,想象一下数百万行和数千个userId,解决方案的效率并不那么重要(因为它不必经常运行)

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. 其次,我刚刚注意到,对结果进行计数实际上并不能保证正确性,因为两个不同的userId可能具有相同的映射计数,但映射到不同的Item。 In that scenario it is not an intersection anymore 在那种情况下,它不再是路口

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. 理想情况下,将两个条件参数化,但这不在此问题的范围内。

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)

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))

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: 您可以避免count distinct ,以及不必多次输入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);

One method is using HAVING : 一种方法是使用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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM