質問

次の表があるとします。

Recipes
| id | name
| 1  | 'chocolate cream pie'
| 2  | 'banana cream pie'
| 3  | 'chocolate banana surprise'

Ingredients
| id | name
| 1  | 'banana'
| 2  | 'cream'
| 3  | 'chocolate'

RecipeIngredients
| recipe_id | ingredient_id
|     1     |      2
|     1     |      3
|     2     |      1
|     2     |      2
|     3     |      1
|     3     |      3

材料名 = 'チョコレート' および材料名 .名 = 'クリーム' であるレシピを検索する SQL クエリを作成するにはどうすればよいですか?

役に立ちましたか?

解決

これを関係分割といいます。さまざまなテクニックが語られています ここ.

まだ与えられていない代替案の 1 つは、二重の NOT EXISTS です。

SELECT r.id, r.name
FROM Recipes r
WHERE NOT EXISTS (SELECT * FROM Ingredients i
                  WHERE name IN ('chocolate', 'cream')
                  AND NOT EXISTS
                      (SELECT * FROM RecipeIngredients ri
                       WHERE ri.recipe_id = r.id
                       AND ri.ingredient_id = i.id))

他のヒント

使用します。

  SELECT r.name
    FROM RECIPES r
    JOIN RECIPEINGREDIENTS ri ON ri.recipe_id = r.id
    JOIN INGREDIENTS i ON i.id = ri.ingredient_id
                      AND i.name IN ('chocolate', 'cream')
GROUP BY r.name
  HAVING COUNT(DISTINCT i.name) = 2
ここで重要なポイントは、カウントは成分名の数に等しくなければならないということです。それは明確な数ではない場合は、原因重複する偽陽性のリスクがあります。

あなたの場合は、複数の関連付けのためにしている検索クエリを作成する最も簡単な方法ではなく、単一のストレートEXISTSの複数JOIN条件を使用することです。

SELECT r.id, r.name
FROM Recipes r
WHERE EXISTS
(
    SELECT 1
    FROM RecipeIngredients ri
    INNER JOIN Ingredients i
        ON i.id = ri.ingredient_id
    WHERE ri.recipe_id = r.id
    AND i.name = 'chocolate'
)
AND EXISTS
(
    SELECT 1
    FROM RecipeIngredients ri
    INNER JOIN Ingredients i
        ON i.id = ri.ingredient_id
    WHERE ri.recipe_id = r.id
    AND i.name = 'cream'
)

あなたは(すなわち、単一のレシピが唯一の各成分の単一のインスタンスを持つことができます)団体が一意であることを確実に知るならば、あなたはCOUNT機能をグループ化するサブクエリを使用してビットをカンニングして、おそらくそれをスピードアップすることができます(パフォーマンス)DBMSに依存します:

SELECT r.id, r.Name
FROM Recipes r
INNER JOIN RecipeIngredients ri
    ON ri.recipe_id = r.id
INNER JOIN Ingredients i
    ON i.id = ri.ingredient_id
WHERE i.name IN ('chocolate', 'cream')
GROUP BY r.id, r.Name
HAVING COUNT(*) = 2

あるいは、レシピは同じ成分(UNIQUEアソシエーションテーブルにはRecipeIngredients制約)の複数のインスタンスを持っている可能性がある場合、あなたが最後の行を置き換えることができます:

HAVING COUNT(DISTINCT i.name) = 2
select r.*
from Recipes r
inner join (
    select ri.recipe_id
    from RecipeIngredients ri 
    inner join Ingredients i on ri.ingredient_id = i.id
    where i.name in ('chocolate', 'cream')
    group by ri.recipe_id
    having count(distinct ri.ingredient_id) = 2
) rm on r.id = rm.recipe_id
SELECT DISTINCT r.id, r.name
FROM Recipes r
INNER JOIN RecipeIngredients ri ON
    ri.recipe_id = r.id
INNER JOIN Ingredients i ON
    i.id = ri.ingredient_id
WHERE
    i.name IN ( 'cream', 'chocolate' )

編集次のコメント、ありがとう!

:これは、右の方法であります
SELECT DISTINCT r.id, r.name
FROM Recipes r
INNER JOIN RecipeIngredients ri ON
    ri.recipe_id = r.id
INNER JOIN Ingredients i ON
    i.id = ri.ingredient_id AND
    i.name = 'cream'
INNER JOIN Ingredients i2 ON
    i2.id = ri.ingredient_id AND
    i2.name = 'chocolate'

別の方法:

バージョン2(ストアドプロシージャなど)

改訂
select   r.name
from   recipes r
where   r.id  = (select  t1.recipe_id
        from  RecipeIngredients t1 inner join
     RecipeIngredients     t2 on t1.recipe_id = t2.recipe_id
     and     t1.ingredient_id = @recipeId1
     and     t2.ingredient_id = @recipeId2)

編集2: [人々が悲鳴を開始する前に]:)

この代わりにIDを渡すの名前クエリに可能になる、バージョン2の上部に配置することができる。

select @recipeId1 = recipe_id from Ingredients where name = @Ingredient1
select @recipeId2 = recipe_id from Ingredients where name = @Ingredient2

私は、バージョン2をテストしてみた、それが動作します。この場合には、成分表にリンクするほとんどのユーザーは、完全に必要ではなかった!

編集3:(試験結果)

このストアドプロシージャを実行すると、

これらの結果です。

の結果は形式である(第Recipe_id;第Recipe_id、結果)

1,1, Failed
1,2, 'banana cream pie'
1,3, 'chocolate banana surprise'
2,1, 'banana cream pie'
2,2, Failed
2,3, 'chocolate cream pie'
3,1, 'chocolate banana surprise'
3,2, 'chocolate cream pie'
3,3, Failed

明らかに、このクエリは、両方の制約が同じである場合を扱うが、他のすべてのケースで動作しません。

編集4:(同じ制約ケースの取り扱い):

この行を置き換えます

r.id = (select t1...

r.id in (select t1...
与えることができなかった例と連携します:

1,1, 'banana cream pie' and 'chocolate banana surprise'
2,2, 'chocolate cream pie' and 'banana cream pie'
3,3, 'chocolate cream pie' and 'chocolate banana surprise'
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top