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