1

鉴于此架构:

 table tblSET 
    SetID int  PK
    SetName nvarchar(100) 


 Table tblSetItem 
    SetID int  PK
    ItemID int PK

tblSetItem.SetID 是 tblSet 表中的 FK。

一些数据:

表集

 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),蓝色天空包含相同的值 (100,108,109)

是否有可以提供此答案的 sql 查询?

4

4 回答 4

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
于 2013-11-07T16:01:42.417 回答
1

我确实假设您需要确定内容完全相同的集合。所以我会去一个临时表,在哪里存储包含项目的“哈希”。散列可能就像以逗号分隔的项目 ID 列表一样简单。

例如。

Set Hash
1   100,101
2   100,108,109
3   100,101
4   101,108,109,110
5   100,108,109

然后,您只需在这样一个按哈希值分组的临时表上进行选择

例如。仅重复集:

Count Hash
2     100,101
2     100,108,109

所以,恢复:

  • 使用 xml 路径函数填充临时表以加入项目 ID(请记住获取项目 ID 的有序列表)

  • 通过计算按哈希分组的行来选择临时表上的重复集

  • 对重复集应用任何后续形式的逻辑

于 2013-11-07T15:46:44.813 回答
1

一个简单的解决方案是计算每个集合的总项目数并进行自连接以计算集合之间共有的项目数。然后只选择它们的总数和交集大小相同的那些对集合。

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
于 2019-08-28T17:11:48.493 回答
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(*)
于 2013-11-07T15:51:31.467 回答