在几行中找到完全匹配的内容

时间:2018-12-19 10:35:42

标签: tsql

我有一个GroupsTable表,可以通过MWE描述如下。

GroupID  MemberID
1        42
2        42
2        43
3        42
3        43
3        44

然后给我另一个表MemberTable,其中包含一些带有MemberID的行。例如:

MemberID
42
43

我需要的查询是从第二个表中找到恰好具有GroupID的匹配MemberID的查询。我相信以下代码可以正常工作,但是速度非常慢,所以有没有更好的方法来找到答案?

select c.GroupID from (
  select g.GroupID 
  from GroupTable g 
  join MemberTable m on m.MemberID = g.MemberID
  group by g.GroupID
  having count(*) = (select count(*) from MemberTable)
) c 
left join GroupTable x on x.GroupID = c.GroupID
and x.MemberID not in (select MemberID from MemberTable)
where x.GroupID is null

样本数据:

create table MemberTable (
  MemberID int
)
insert into MemberTable
values 
(42), 
(43);

create table GroupTable (
  GroupID int,
  MemberID int
);
insert into GroupTable 
values 
(1, 42), -- only one member
(2, 42), -- both members
(2, 43), 
(3, 42), -- one member too many
(3, 43),
(3, 44),
(4, 40), -- two irrelevant members
(4, 41);

这里有一个小提琴:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=ad818a306600286433634fa83c3628a0

1 个答案:

答案 0 :(得分:1)

您可以结合使用左联接,分组依据,拥有和计数,如下所示:

DECLARE @Count int;
SELECT @Count = COUNT(*) FROM MemberTable;

SELECT GroupID 
FROM GroupTable As G
LEFT JOIN  MemberTable As M
    ON G.MemberID = M.MemberID
GROUP BY GroupID
HAVING COUNT(DISTINCT G.MemberID) = @Count 
AND  COUNT(DISTINCT M.MemberID) = @Count 

左联接确保您将获取每个组ID的所有记录。

不同的组成员ID数目确保您将仅获得没有成员ID不在成员表中的组ID。

members表的不同计数确保您不会获得恰好具有与members表相同数量的id的组。

更新

在我自己的环境中使用临时表进行测试之后,我证实了自己的怀疑,即性能杀手是count(distinct)。我已更改查询以摆脱它,现在它的速度似乎几乎是问题中查询的两倍:

DECLARE @Count int;
SELECT @Count = COUNT(*) FROM MemberTable;

SELECT GroupID 
FROM 
(
    SELECT DISTINCT GroupID, MemberID
    FROM GroupTable
) As G
LEFT JOIN 
(
    SELECT DISTINCT MemberID
    FROM MemberTable
) As M
    ON G.MemberID = M.MemberID
GROUP BY GroupID
HAVING COUNT(G.MemberID) = @Count 
AND  COUNT(M.MemberID) = @Count;

请注意,如果已知MemberTable始终具有不同的MemberID值,则可以摆脱第二个派生表,而只需将第一个派生表直接连接到MemberTable