我有多个表,由多个外键相关,如下例所示:
and
- Recipes(id_recipe,name,calories,category)
为PK。id_recipe
- Ingredients(id_ingredient,name,type)
为PK。id_ingredient
- Contains(id_ingredient,id_recipe,quantity,unit)
为PK,以及(id_ingredient,id_recipe)
和Recipes(id_recipe)
的外键。您可以在此图片中看到此关系。
所以基本上Ingredients(id_ingredient)
是Contains
和Recipes
之间的桥梁。
我试图写它的查询应该给出其成分类型为“牛”但不是“乳酸”的食谱的名称。
我的尝试:
Ingredients
问题是它仍然向我展示了至少含有一种乳酸成分的食谱。
我将不胜感激任何帮助!
答案 0 :(得分:1)
这是您需要的查询类型的一般形式:
SELECT *
FROM tableA
WHERE tableA.ID NOT IN (
SELECT table_ID
FROM ...
)
;
- 以下示例 -
子查询给出了" lactic"的所有食谱的id值。使用成分,外部查询说"给我所有不在该列表中的食谱"。
SELECT DISTINCT Recipes.name
FROM Recipes
WHERE id_recipe IN (
SELECT DISTINCT id_recipe
FROM `Ingredients` AS `i`
INNER JOIN `Contains` AS `c` USING (id_ingredient)
WHERE `i`.`type` = "lactic"
)
;
或者,使用原始查询:
您可以将第二次加入更改为LEFT JOIN
,将其USING
更改为ON
&相反,包含AND type = "lactic"
,并以HAVING Ingredients.type IS NULL
结束查询(或者WHERE,我只是喜欢HAVING for"最终结果"过滤)。这会告诉你哪些物品无法加入"乳酸"成分
答案 1 :(得分:1)
此类问题的常见解决方案(检查一组行的条件)使用聚合+ CASE。
SELECT R.Name
FROM Recipes R
INNER JOIN Contains C
on R.ID_Recipe = C.ID_Recipe
INNER JOIN Ingredients I
on C.ID_Ingredient = I.ID_Ingredient
GROUP BY R.name
having -- at least one 'lactic' ingredient
sum(case when type = 'lactic' then 1 else 0 end) = 0
and -- no 'bovin' ingredient
sum(case when type = 'bovin' then 1 else 0 end) > 0
很容易扩展到任何数量的成分和任何类型的问题。
劫持了xQbert的fiddle
答案 2 :(得分:0)
SELECT R.NAME
FROM CONTAINS C
INNER JOIN INGREDIENTS I
ON I.ID_INGREDIENTS = C.ID_INGREDIENTS AND I.TYPE = 'bovine' AND I.TYPE <> "lactic"
INNER JOIN RECIPES R
ON R.ID_RECIPE = C.ID_RECIPE
GROUP BY R.NAME
这应该有用,也许你需要逃避'包含'。它可以被识别为SQL函数。
答案 3 :(得分:0)
SQL Fiddle 在我的例子中汉堡和意大利面有&#39; Bovin&#39;从而出现。饼干也是如此,但饼干也有“乳酸”。这就是他们被排除在外的原因。
SELECT R.Name
FROM Recipes R
INNER JOIN Contains C
on R.ID_Recipe = C.ID_Recipe
INNER JOIN Ingredients I
on C.ID_Ingredient = I.ID_Ingredient
LEFT JOIN (SELECT R2.ID_Recipe
FROM Ingredients I2
INNER JOIN Contains C2
on C2.ID_Ingredient = I2.ID_Ingredient
INNER JOIN Recipes R2
on R2.ID_Recipe = C2.ID_Recipe
WHERE Type = 'lactic'
GROUP BY R2.ID_Recipe) T3
on T3.ID_Recipe = R.ID_Recipe
WHERE T3.ID_Recipe is null
and I.Type = 'Bovin'
GROUP BY R.name
可能有更优雅的方式来做到这一点。我真的想CTE这个加入它自己..但在mySQL中没有CTE。可能使用存在的方法也是如此....我不是使用IN子句的忠实粉丝,因为性能通常会受到影响。存在最快,加速第二快,最慢(一般来说)
内联视图(子查询)返回您不想包含的ID_recipe。
外部查询返回所需配料的食谱名称。
通过使用外部连接将这两者连接在一起,我们返回所有配方,只返回含有不需要成分的配方。然后,我们将结果限制为仅针对不需要的成分不存在配方ID的结果。 (没有找到不需要的成分)你只能得到那些含有所有所需成分的食谱。
答案 4 :(得分:0)
您可以使用NOT EXISTS
。
试试这个:
SELECT DISTINCT Recipes.`name`
FROM Recipes JOIN Contains AS C1 USING (id_recipe) JOIN Ingredients USING(id_ingredient)
WHERE Ingredients.type = "bovin"
AND NOT EXISTS (
SELECT 1
FROM Contains AS C2 JOIN Ingredients USING(id_ingredient)
WHERE C1.id_recipe = C2.id_recipe
AND Ingredients.type = "lactic"
)