给出这个架构:
table tblSET
SetID int PK
SetName nvarchar(100)
Table tblSetItem
SetID int PK
ItemID int PK
tblSetItem.SetID是进入tblSet表的FK。
一些数据:
tblSet
SetID SetName
1 Red
2 Blue
3 Maroon
4 Yellow
5 Sky
tblSetItem
SetID ItemID
1 100
1 101
2 100
2 108
2 109
3 100
3 101
4 101
4 108
4 109
4 110
5 100
5 108
5 109
我想要一种方法来识别哪些集合包含相同的项目。在上面的示例中,红色和褐色包含相同的项目(100,101)和蓝色,天空包含相同的值(100108109)
是否有提供此答案的SQL查询?
答案 0 :(得分:2)
您可以使用xml支持创建逗号分隔列表(参见此答案:https://stackoverflow.com/a/1785923/215752)。对于这种情况,我不关心表单,所以我将起始逗号留在。
注意,我现在无法测试这个,所以我可能会输入错误...
select * from
(
select SetID, setitemuniquestring,
count(*) OVER (PARTITION BY setitemuniquestring) as cnt
from
(
select S.SetID,
(select ',' + I.ItemID
from tblSetItem I
where S.SetID = I.SetID
order by u.ItemID ASC
for xml path('')
) as setitemuniquestring
from tblSet S
group by S.SetID
) sub
) sub2
where cnt > 2
答案 1 :(得分:1)
我认为您需要识别哪些内容完全相同的集合。 所以我会去临时表,在哪里存储所包含项的“哈希”。 散列可能与逗号分隔的项ID列表一样简单。
例如
Set Hash
1 100,101
2 100,108,109
3 100,101
4 101,108,109,110
5 100,108,109
然后,您只需通过哈希值
选择这样的临时表分组EG。 仅限重复集:
Count Hash
2 100,101
2 100,108,109
所以,恢复:
使用xml路径函数填充临时表来连接项目ID(记得获取项目ID的有序列表)
通过计算按哈希分组的行
在您的副本集上应用任何后续形式的逻辑
答案 2 :(得分:0)
您可以使用单个查询执行此操作。我接近它的方法是创建所有对集合。然后使用外连接两次加入项目,每侧一次。
然后,由两个集合ID聚合。当任何一方都没有空值时,这些项目是相同的。有不同的方法来检查这一点。以下使用count(*)
进行该检查:
select pairs.SetId1, pairs.SetId2
from (select s.SetId as SetId1, s2.SetId as SetId2
from tblSetItem s cross join tblSetItem s2
) pairs left outer join
tblSetItem si1
on pairs.SetId1 = si1.SetId1 full outer join
tblSetItem si2
on pairs.SetId2 = si2.SetId2 and si2.ItemId = si1.ItemId
group by pairs.SetId1, pairs.SetId2
having count(si1.SetId) = count(si2.Setid) and
count(si1.SetId) = count(*)
答案 3 :(得分:0)
一个简单的解决方案是对每个集合的总数进行计数,并进行自我联接以计算集合之间共有的项目数。然后只选择总和相交大小相同的那些对集。
SELECT *
FROM (SELECT a_id, b_id, a.cnt
FROM (SELECT SetId as a_id, count(*) as cnt
FROM tblSetItem GROUP BY SetId) as a,
(SELECT SetId as b_id, count(*) as cnt
FROM tblSetItem GROUP BY SetId) as b
WHERE a.cnt=b.cnt AND a_id!=b_id) as totals_match
NATURAL JOIN
(SELECT a.SetId as a_id, b.SetId as b_id, count(*) as cnt
FROM tblSetItem a, tblSetItem b
WHERE a.SetId != b.SetId and a.ItemId=b.ItemId) as items_match