これを行うのにより適したスキーマがあるかどうかについてはコメントしませんが(それはかなり可能です)、列がname
のスキーマの場合です。 およびitem
、次のクエリが機能するはずです。 (mysql構文)
SELECT k.name
FROM (SELECT DISTINCT name FROM sets) AS k
INNER JOIN sets i1 ON (k.name = i1.name AND i1.item = 1)
INNER JOIN sets i2 ON (k.name = i2.name AND i2.item = 3)
INNER JOIN sets i3 ON (k.name = i3.name AND i3.item = 5)
LEFT JOIN sets ix ON (k.name = ix.name AND ix.item NOT IN (1, 3, 5))
WHERE ix.name IS NULL;
k
にすべての設定キーがあるという考え方です。 、次にsets
のセットアイテムデータと結合します 検索するセット内のセットアイテムごとに1回、この場合は3回。テーブルエイリアスi1
を使用した3つの内部結合のそれぞれ 、i2
およびi3
その結合で検索されたアイテムを含まないすべてのセット名を除外します。最後に、sets
との左結合があります テーブルエイリアスix
、セット内のすべての追加アイテム、つまり、検索していなかったすべてのアイテムを取り込みます。 ix.name
NULL
です 余分なアイテムが見つからない場合、これはまさに私たちが望んでいることであり、したがってWHERE
句。クエリは、セットが見つかった場合はセットキーを含む行を返し、それ以外の場合は行を返しません。
編集: 崩壊者の答えの背後にある考え方は私のものよりもはるかに優れているように思われるので、ここに説明付きの少し短いバージョンがあります。
SELECT sets.name
FROM sets
LEFT JOIN (
SELECT DISTINCT name
FROM sets
WHERE item NOT IN (1, 3, 5)
) s1
ON (sets.name = s1.name)
WHERE s1.name IS NULL
GROUP BY sets.name
HAVING COUNT(sets.item) = 3;
ここでの考え方は、サブクエリs1
探しているもの以外のアイテムを含むすべてのセットのキーを選択します。したがって、join sets
を離れると s1
を使用 、s1.name
NULL
です セットに検索対象のアイテムのみが含まれている場合。次に、セットキーでグループ化し、アイテム数が間違っているセットを除外します。次に、検索しているアイテムのみを含み、正しい長さのセットのみが残ります。セットにはアイテムを1回しか含めることができないため、その条件を満たすセットは1つだけであり、それが私たちが探しているものです。
編集: 除外せずにこれを行う方法に気づきました。
SELECT totals.name
FROM (
SELECT name, COUNT(*) count
FROM sets
GROUP BY name
) totals
INNER JOIN (
SELECT name, COUNT(*) count
FROM sets
WHERE item IN (1, 3, 5)
GROUP BY name
) matches
ON (totals.name = matches.name)
WHERE totals.count = 3 AND matches.count = 3;
最初のサブクエリは各セットのアイテムの総数を検索し、2番目のサブクエリは各セットの一致するアイテムの数を検索します。 matches.count
の場合 が3の場合、セットには探しているすべてのアイテムが含まれ、totals.count
の場合 も3で、セットには余分なアイテムはありません。