2

テーブルにデータを書き込み、書き込まれたデータのバッチごとに「グループ ID」を割り当てています。説明のために、次の表を検討してください。

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

この例では、データの 3 つのグループがあり、それぞれが似ているが異なる値を持っています。

このテーブルにクエリを実行して、特定の値のセットを含むグループを見つけるにはどうすればよいですか? たとえば、(a,b,c) をクエリすると、結果はグループ 1 になります。同様に、(b,a) をクエリするとグループ 2 になり、(a, b, c, e) をクエリするとグループ 2 になります。空のセットになるはずです。

次の手順を実行するストアド プロシージャを作成できます。

  • Groups から個別の GroupId を選択し、ローカルに保存します
  • 個別の GroupId ごとに:except入力値とテーブル値 (グループの場合) の間で set-difference ( ) を実行し、その逆も同様です。
  • set-difference 操作の両方で空のセットが生成された場合は GroupId を返します

これは少しやり過ぎに思えます。単純化するために SQL の他のコマンドを活用したいと考えています。このコンテキストでセット比較を実行する、またはクエリの正確な入力値を含むグループ ID を選択する簡単な方法はありますか?

4

2 に答える 2

4

これは set-with-sets クエリです。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;

句の最初の 3 つの条件は、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

これはちょっと醜いですが、うまくいきます。大規模なデータセットでは、パフォーマンスがどのようになるかはわかりませんが、メイン テーブルの#GroupValuesキー オフのネストされたインスタンスGroupIDなので、適切なインデックスがある限り、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 に答える