2

我正在将数据写入表并为每批写入的数据分配一个“组 ID”。为了说明,请考虑下表。

GroupId  Value
-------  -----
      1      a
      1      b
      1      c
      2      a
      2      b
      3      a
      3      b
      3      c
      3      d

在此示例中,有三组数据,每组具有相似但不同的值。

如何查询此表以查找包含给定值集的组?例如,如果我查询 (a,b,c),结果应该是第 1 组。同样,查询 (b,a) 应该导致第 2 组,查询 (a,b,c,e)应该导致空集。

我可以编写一个执行以下步骤的存储过程:

  • 从 Groups 中选择不同的 GroupId - 并在本地存储
  • 对于每个不同的 GroupId:except在输入值和表值(对于组)之间执行集差 (),反之亦然
  • 如果两个集合差异操作都产生空集合,则返回 GroupId

这似乎有点过分,我希望利用 SQL 中的其他一些命令来简化。在这种情况下是否有更简单的方法来执行集合比较,或者选择包含查询的确切输入值的组 ID?

4

2 回答 2

4

这是一个集合内集合查询。我喜欢使用group byand来解决它having

select groupid
from GroupValues gv
group by groupid
having sum(case when value = 'a' then 1 else 0 end) > 0 and
       sum(case when value = 'b' then 1 else 0 end) > 0 and
       sum(case when value = 'c' then 1 else 0 end) > 0 and
       sum(case when value not in ('a', 'b', 'c') then 1 else - end) = 0;

子句中的前三个条件having检查每个元素是否存在。最后一个条件检查没有其他值。此方法非常灵活,适用于您要查找的值的各种排除和包含条件。

编辑:

如果要传入列表,可以使用:

with thelist as (
      select 'a' as value union all
      select 'b' union all
      select 'c'
     )
select groupid
from GroupValues gv left outer join
     thelist
     on gv.value = thelist.value
group by groupid
having count(distinct gv.value) = (select count(*) from thelist) and
       count(distinct (case when gv.value = thelist.value then gv.value end)) = count(distinct gv.value);

这里的having子句计算匹配值的数量,并确保它与列表的大小相同。

编辑:查询编译失败,因为缺少表别名。使用正确的表别名更新。

于 2014-02-28T19:59:17.160 回答
1

这有点丑陋,但它有效。在较大的数据集上,我不确定性能会是什么样子,但是主表中的嵌套实例#GroupValueskey offGroupID所以我认为只要你有一个好的索引,GroupID它可能不会太可怕。

If      Object_ID('tempdb..#GroupValues') Is Not Null Drop Table #GroupValues
Create  Table #GroupValues (GroupID Int, Val Varchar(10));
Insert  #GroupValues (GroupID, Val)
Values  (1,'a'),(1,'b'),(1,'c'),(2,'a'),(2,'b'),(3,'a'),(3,'b'),(3,'c'),(3,'d');

If      Object_ID('tempdb..#FindValues') Is Not Null Drop Table #FindValues
Create  Table #FindValues (Val Varchar(10));
Insert  #FindValues (Val)
Values  ('a'),('b'),('c');

Select  Distinct gv.GroupID
From   (Select  Distinct GroupID 
        From    #GroupValues) gv
Where   Not Exists (Select  1
                    From    #FindValues fv2
                    Where   Not Exists (Select  1
                                        From    #GroupValues gv2
                                        Where   gv.GroupID = gv2.GroupID
                                        And     fv2.Val = gv2.Val))
And     Not Exists (Select  1
                    From    #GroupValues gv3
                    Where   gv3.GroupID = gv.GroupID
                    And     Not Exists (Select  1
                                        From    #FindValues fv3
                                        Where   gv3.Val = fv3.Val))
于 2014-02-28T21:09:35.030 回答