2

実際に非常に簡単なSQLステートメントを作成しようとすると、自分自身が失われてしまいます。

3つのテーブルを持つデータベースを取得しました。

  • レシピ-料理用のレシピ名を保存する
  • 材料_レシピ-材料とレシピをリンクします
  • 材料-レシピで使用される材料。

二重にクリアにするために、次のように保存されます。

レシピ:

id | 名前
 1 | ラザニアアラボロネーゼ
 2 | トマトとマグロ

材料:

id | 名前
 1 | ラザニアスライス
 2 | 肉
 3 | トマト
 4 | ツナ

と参加テーブルの材料_レシピ:

成分ID| レシピID
            1 | 1
            2 | 1
            3 | 1
            3 | 2
            4 | 2

ご覧のとおり、少なくともいくつかのスパイスを与える必要がある2つの本当に非デリシオなレシピがあります。でも前にやりたいのは具材でレシピを選ぶことです。

私はすべてのレシピに肉トマトを入れたいです:

SELECT recipes.name FROM recipes r
INNER JOIN ingredients_recipes ir ON ir.recipes_id = r.id
WHERE ir.ingredient_id IN ( 2 ) AND ir.ingredient_id IN ( 3 )

->ラザニア..元気!(「トマト」、「トマト」、「トマト、スライス」などの材料がたくさんある可能性があるため、INを使用します。)

たとえば、トマトはあるがマグロはないすべてのレシピが必要な場合は、次のことを試しました。

SELECT recipes.name FROM recipes r
INNER JOIN ingredients_recipes ir ON ir.recipes_id = r.id
WHERE ir.ingredient_id IN ( 2 ) AND ir.ingredient_id NOT IN ( 4 )

->まだマグロを手に入れています-私が参加する行の1つに材料4が含まれていないためです。わかりました:/

私が今疑問に思っているのは、希望する結果を得るために何をしなければならないかということです。私は現在、次のような副選択を行うことで膝に矢印を付けています。

SELECT recipes.name FROM recipes r
INNER JOIN ingredients_recipes ir ON ir.recipes_id = r.id
WHERE (
        ir.ingredient_id IN ( 2 ) -- or more..
        AND 
        recipes.id NOT IN ( SELECT recipes_id FROM ingredients_recipes
                             WHERE ingredient_id IN ( 4 ) -- actually i paste names of the ingredients.. but that is not the case. just to shorten the query.. by filling in a comment twice as long..
                            )
      )

私はmySQLにまったく慣れていないので、何をグーグルで検索すればよいのかさえわかりません。したがって、その場合のヘルプ、およびo/cより良いSQLステートメントは..

 IN(awesome).

編集:ああ、そしてはい、私は実際にグループ化を行います.. ;-)

4

2 に答える 2

2

これは一つの方法です。(未テスト)

SELECT r.name 
FROM recipes r
JOIN ingredients_recipes ir 
  ON ir.recipe_id = r.id
WHERE EXISTS ( SELECT *
    FROM ingredients_recipes ex
    WHERE ex.recipe_id = r.recipe_id
    AND ex.ingredient_id IN ( 2 , 3 )
    GROUP BY nx.recipe_id
    HAVING COUNT(*) = 2
    );

count(*) が 2 になる唯一の方法は、2 と 3 の両方が存在する場合です。

別の方法は次のとおりです。(まだテストされていません)

SELECT r.name 
FROM recipes r
JOIN ingredients_recipes ir 
  ON ir.recipe_id = r.id
WHERE EXISTS ( SELECT *
    FROM ingredients_recipes ex
    WHERE ex.recipe_id = r.recipe_id
    AND ex.ingredient_id = 2
    )
AND EXISTS ( SELECT *
    FROM ingredients_recipes ex
    WHERE ex.recipe_id = r.recipe_id
    AND ex.ingredient_id = 3
    );

更新:(私は質問を誤解していました)特定の材料が存在するレシピも必要ない場合は、クエリにさらに別のサブクエリ「レッグ」を追加できます:

... AND NOT EXISTS ( SELECT *
    FROM ingredients_recipes ex
    WHERE ex.recipe_id = r.recipe_id
    AND ex.ingredient_id IN ( 4,5 )
    );
于 2012-06-24T22:01:43.787 に答える
2

この柔軟なソリューションを試してください。

1このクエリは、材料 と の両方を含み、材料とを含ま2ないレシピを取得し4ます5

SELECT
    a.*
FROM 
    (
        SELECT aa.id, aa.name
        FROM recipes aa
        INNER JOIN ingredients_recipes bb ON aa.id = bb.recipe_id
        WHERE bb.ingredient_id IN (1,2) --Ingredients to contain
        GROUP BY aa.id, aa.name
        HAVING COUNT(*) = 2 --Count of items in containing list
    ) a
LEFT JOIN
    ingredients_recipes b ON 
        a.id = b.recipe_id AND
        b.ingredient_id IN (4,5) --Ingredients to NOT contain
WHERE 
    b.recipe_id IS NULL

説明:

FROMsubselect は、成分との両方を含むすべてのレシピを取得します。レシピに含まれる材料を追加または削除する場合は、リスト内の成分 ID を調整し、値がそのリスト内のアイテムの数を表していることを確認してください。ここで行っているのは、成分 1 または 2 のいずれかを含むレシピを選択することです。つまり、一部のレシピは 1 行 (1 つの成分のみを含み、他の成分を含まない場合) または 2 行 (両方の成分を含む場合) で結合します。次に、 2 つの行で結合されたレシピのみが選択されます。12INCOUNT(*)HAVING COUNT(*) = 2

これらのレシピが選択されたら、材料と を含まないレシピを除外する必要があります。これは/で行います。副選択と同様に、リストの成分を追加または削除できますが、 の aを調整する必要はありません。45LEFT JOINIS NULLFROMINCOUNTLEFT JOIN

于 2012-06-24T22:15:35.613 に答える