我有两个表,一个包含不同的食谱,另一个包含recipes_ingredients(食谱所需的所有成分)。
Sql Azure Db
让我们说我只选择了一种成分(例如鸡蛋)。
Azure VM Sql
这会返回包含鸡蛋的所有食谱。这是合乎逻辑的,但我想创建一个查询,返回 ONLY 包含鸡蛋(例如煮鸡蛋)的所有食谱。不是一些将鸡蛋作为其中一部分的食谱。
如果我同时选择鸡蛋和牛奶并创建相同的查询:
recipes
-----
id_recipe
name
description
etc...
recipe_ingredients
-----
id_recipe_ingredient
id_recipe
id_ingredient
我会找到煎蛋卷,但我也会找到所有其他含有鸡蛋和牛奶的食谱。
我想选择的是:
仅包含鸡蛋的食谱
仅包含鸡蛋和牛奶的食谱
我不想选择含有鸡蛋,牛奶,面粉和糖的蛋糕。
感谢任何可能让我朝着正确方向前进的答案!
答案 0 :(得分:4)
计算配料的数量和配料的数量,并检查它们是否匹配。例如,要检索包含成分1和2以及仅包含这两种成分的所有配方:
SELECT id_recipe
FROM recipe_ingredients
GROUP BY id_recipe
HAVING COUNT(*) = 2
AND COUNT(CASE WHEN id_ingredient IN (1, 2) THEN 1 END) = COUNT(*);
您还可以使用GROUP_CONCAT
将成分ID收集到字符串中并进行字符串比较:
SELECT id_recipe
FROM recipe_ingredients
GROUP BY id_recipe
HAVING GROUP_CONCAT(id_ingredient ORDER BY id_ingredient) = '1,2';
在前面的查询中,为了便于阅读,我省略了完整的配方检索。为完整起见,以下查询将检索完整的配方:
SELECT *
FROM recipes JOIN recipe_ingredients USING (id_recipe)
WHERE id_recipe in (
SELECT id_recipe
FROM recipe_ingredients
GROUP BY id_recipe
HAVING COUNT(*) = 2
AND COUNT(CASE WHEN id_ingredient IN (1, 2) THEN 1 END) = COUNT(*)
);
虽然这些查询简短且易读,但如果您有大量食谱和/或成分,则可能会遇到性能问题。如果这样做,您可能希望在id_ingredient
和id_recipe
上添加索引并尝试将查询重写为
SELECT *
FROM recipes JOIN recipe_ingredients USING (id_recipe)
WHERE id_recipe in (
SELECT i1.id_recipe
FROM recipe_ingredients i1
JOIN recipe_ingredients i2
ON (i1.id_recipe = i2.id_recipe AND i2.id_ingredient = 2)
LEFT JOIN recipe_ingredients ni
ON (i1.id_recipe = ni.id_recipe and ni.id_ingredient NOT IN (1, 2))
WHERE i1.id_ingredient = 1 AND ni.id_ingredient IS NULL
);
但是,我发现这个版本更加繁琐且难以维护,并建议在性能需要之前避免使用它。
答案 1 :(得分:1)
获得EGG和MILK只含有2种成分的产品和含有EGG且只含一种成分的UNION ........
SELECT r.Id, COUNT(ri.Id) FROM recipes r --GET THE RECIPE ID AND COUNT OF INGREDIENTS
INNER JOIN recipes_ingredients ri ON r.id_recipe = ri.id_recipe --JOIN RECIPE INGREDIENTS
WHERE
ri.id_ingredient IN (1,2) --EGGS OR MILK
AND r.id NOT IN (SELECT ri2.id FROM recipes_ingredients ri2 WHERE ri2.id NOT IN (1,2)) --AND JUST EGGSD OR MILK
HAVING COUNT(ri.Id) = 2 --AND THERE ARE 2 INGREDIENTS
UNION ALL
SELECT r.Id, COUNT(ri.Id) FROM recipes r --GET THE RECIPE ID AND COUNT OF INGREDIENTS
INNER JOIN recipes_ingredients ri ON r.id_recipe = ri.id_recipe --JOIN RECIPE INGREDIENTS
WHERE
ri.id_ingredient = 1 --EGGS
AND r.id NOT IN (SELECT ri2.id FROM recipes_ingredients ri2 WHERE ri2.id !=1) --AND JUST EGGS
HAVING COUNT(ri.Id) = 1
答案 2 :(得分:1)
查询单个成分,并确保通过将查询中的成分数量与配方成分的数量相匹配,不再有任何成分。
修改强>
逐个配对所需的成分,以确保所有这些成分都存在于所讨论的配方中。如果它们都存在并且配料的数量匹配,那么就不会有任何更多或更少的成分。
select *
from recipe_table rt
where rt.id_recipe in (select rig.id_recipe
from recipe_ingredient_table rig
where rig.id_recipe = rt.id_recipe
and <ing_id_1> in (select rig2.id_ingredient from recipe_ingredient_table rig2 where rig2.id_recipe = rig.id_recipe)
and <ing_id_2> in (select rig2.id_ingredient from recipe_ingredient_table rig2 where rig2.id_recipe = rig.id_recipe)
and ...
and (select count(*)
from recipe_ingredient_table
where id_recipe = rig.id_recipe) = <number of ingredients>
)
答案 3 :(得分:-1)
-- 1 egg only
SELECT *
FROM recipes AS r
WHERE EXISTS (
SELECT ri.id_recipe, count(*)
FROM recipes_ingredients AS ri
WHERE ri.id_recipe = id_recipe
AND ri.id_ingredient = 1
GROUP BY ri.id_recipe
HAVING COUNT(*) = 1
)
-- 1 egg only OR 2 milk only OR egg and milk
SELECT *
FROM recipes AS r
WHERE EXISTS (
SELECT ri.id_recipe, count(*)
FROM recipes_ingredients AS ri
WHERE ri.id_recipe = id_recipe
AND ri.id_ingredient IN (1, 2)
GROUP BY ri.id_recipe
HAVING COUNT(*) < 3
)
-- both egg and milk only
-- change above SQL: HAVING COUNT(*) = 2