SQL Server 查找包含的组
Posted
技术标签:
【中文标题】SQL Server 查找包含的组【英文标题】:SQL Server find contained groups 【发布时间】:2019-05-24 15:40:16 【问题描述】:我正在尝试仅选择不包含在其他组中的组。
在此示例中,组 2 包含在组 1 中,因为组 1 具有组 2 的所有值。
组号 3 不包含在组号 1 中,因为它具有组号 1 不包含的值 50。
结果应该是第 1 组和第 3 组。
(或相反-仅获取包含在其他组中的组号 2)
寻找一种不循环的方式,因为我有超过 200 万个值。
我的桌子是这样的:
group_number id
-------------------
1 10
1 20
1 30
1 40
2 10
2 40
3 10
3 30
3 50
【问题讨论】:
【参考方案1】:我已经使用您提供的数据集进行了测试,并且可以正常工作。 第一个,不包含在另一个组中的组:
SELECT DISTINCT Group_Number FROM #T
WHERE NOT EXISTS (SELECT Group_Number G2
FROM #T AS T2
WHERE T2.Group_Number <> #t.Group_Number
AND T2.ID = #T.ID)
而且...另一种方法很容易拥有这个:
SELECT DISTINCT Group_Number FROM #T WHERE NOT Group_Number IN (
SELECT DISTINCT Group_Number FROM #T
WHERE NOT EXISTS (SELECT Group_Number G2
FROM #T AS T2
WHERE T2.Group_Number <> #t.Group_Number
AND T2.ID = #T.ID)
)
只是问自己,我意识到我的回答并不完全准确。 首先,我意识到添加:
INSERT INTO #t
VALUES (6, 50),
(7, 60),
(8, 50),
(8, 60)
第 8 组没有出现,因为其中一项出现在第 6 组中,而另一项出现在第 7 组中。 所以,我做了很多检查,得出的结论是,下面的代码是保证结果的代码,也提供了可追溯性来验证响应是否正确:
SELECT DISTINCT Group_Number FROM
(
SELECT T1.Group_Number, T1.Rows, T2.Group_Number as Comparing_With_Other_Group, Count(DISTINCT T2.ID) AS Rows_On_Other_Group
FROM (
SELECT Group_Number, Count(DISTINCT ID) AS Rows
FROM #T
GROUP BY Group_Number
) T1
INNER JOIN #T AS T2
ON T1.Group_Number <> T2.Group_Number
AND EXISTS (SELECT 1 FROM #T WHERE #T.Group_Number = T1.Group_Number and #T.ID = T2.ID)
GROUP BY T1.Group_Number, T2.Group_Number, T1.Rows
) SubQry
WHERE Rows = Rows_On_Other_Group
如果您仅运行 SubQry,您将看到可追溯性,而完整查询将向您显示系统可以找到另一个组的组,该组过滤我正在搜索的组中的 ID,找到相同数量的身份证。
【讨论】:
【参考方案2】:您可以尝试以下查询。
SELECT DISTINCT Group_Number FROM #temp
WHERE NOT EXISTS (SELECT DISTINCT Group_Number G2
FROM #temp AS T2
WHERE T2.Group_Number <> #temp.Group_Number
AND T2.ID = #temp.ID)
输出是-
Group_Number
1
3
Demo
【讨论】:
【参考方案3】:我已经使用计数逻辑达到了你的逻辑。
create table grp(a int ,b int)
insert into grp
select 1,10 union
select 1,20 union
select 1,30 union
select 1,40 union
select 2,10 union
select 2,40 union
select 3,10 union
select 3,30 union
select 3,50
drop table #temo
select distinct b.a as d ,b.b as g into #temo
from grp a inner join grp b on (a.a<>b.a and a.b=b.b)
where a.a <> b.a
select a from grp
except
select a.d from (
select d,count(tt) as cnt from (
select d,g,row_number() over (partition by d order by d) tt from
#temo
)rr
group by d) a inner join (select a,count(a) as cnt from grp
group by a) b on a.d=b.a and a.cnt=b.cnt
希望这会有所帮助。
【讨论】:
【参考方案4】:每个组号代表一个集合,您要检查给定集合是否是另一个集合的子集。您可以将表与自身连接以将每个集合与所有其他集合匹配,并使用左连接 + 计数来确定 A 是否是 B 的子集(组中的每一行 A 在组 B 中有匹配的行):
SELECT a.group_number
FROM t AS a
INNER JOIN (
SELECT DISTINCT group_number
FROM t
) AS x ON x.group_number <> a.group_number
LEFT JOIN t AS b ON b.group_number = x.group_number AND b.id = a.id
GROUP BY a.group_number, x.group_number
HAVING COUNT(a.id) = COUNT(b.id)
以上返回的组 ID 是另一个组的子集(在您的示例中为 2)。在 NOT IN
中使用上述内容来获取非子集组 ID。
【讨论】:
以上是关于SQL Server 查找包含的组的主要内容,如果未能解决你的问题,请参考以下文章
为啥当 WHERE 子句包含参数化值时 SQL Server 使用索引扫描而不是索引查找