これを行うのにより適したスキーマがあるかどうかについてはコメントしませんが(それはかなり可能です)、列が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で、セットには余分なアイテムはありません。