在尝试创建一个非常简单的SQL语句时,我发现自己已经迷失了。
我有一个包含3个表的数据库:
它的存储方式使其更加清晰:
配方:
id | name 1 | lasagne alla bolognese 2 | tuna with tomatoes
成分:
id | name 1 | lasagne slices 2 | meat 3 | tomato 4 | tuna
和join-table ingredients_recipes:
ingredient_id | recipes_id 1 | 1 2 | 1 3 | 1 3 | 2 4 | 2
正如你所看到的,有2种真正的unlicios食谱我应该至少给一些香料。但我之前想做的是按成分选择食谱。
我希望我的所有食谱都有肉类和番茄:
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 )
- >仍然得到金枪鱼 - 因为我加入的其中一行不含成分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).
编辑:啊,是的,我实际上是在分组..; - )
答案 0 :(得分: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
);
更新:(我误读了这个问题)如果您还不想要使用特定成分 present 的食谱,您可以在查询中添加另一个子查询“leg”:
... AND NOT EXISTS ( SELECT *
FROM ingredients_recipes ex
WHERE ex.recipe_id = r.recipe_id
AND ex.ingredient_id IN ( 4,5 )
);
答案 1 :(得分: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
FROM
子选择获取 包含 成分1
和2
的所有食谱。如果您希望添加或删除要包含的配方的成分,只需调整IN
列表中的ingredient_ids,并确保COUNT(*)
中的值表示该列表中的项目数。它在这里做的是选择包含 成分1或2的食谱,这意味着一些食谱将只加入1行(如果它只包含一种成分而不是另一种),或者2行(如果它含有两种成分)。然后,HAVING COUNT(*) = 2
仅选择加入 2 行的食谱。
选择这些食谱后,我们现在必须过滤掉不包含成分4
和5
的食谱。我们使用LEFT JOIN
/ IS NULL
执行此操作。与FROM
子选择一样,您可以在IN
列表中添加或删除成分,但不必担心调整COUNT
中的LEFT JOIN
。