SQL查找重复集

时间:2013-11-07 15:34:46

标签: sql sql-server-2008-r2

给出这个架构:

 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查询?

4 个答案:

答案 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