SQL 查询含有这些成分的食谱)但不是这些成分)
SQL query recipes with these ingredient(s) but NOT these ingredient(s)
我正在为用户可以查询的食谱网站做一个高级搜索功能;
- 食谱含有某些成分(最多 3 种成分)
- 食谱不含某些成分(最多 3 种成分)
- 在特定的烹饪时间下
以上几点可以在用户查询中结合在一起。
我已经完成了一半,我可以查询包含指定成分并在一定时间内烹制的食谱。
这是我的数据库结构;
Table:食谱
Recipe_ID、Recipe_Name、Cooking_time
Table:成分
Ingredient_ID、Ingredient_Name
Table: Recipe_Ingredients
食谱_Ingredient_ID、Ingredient_ID、Recipe_ID
这是我目前的 SQL 查询;
SELECT count(*) as rowcount, r.Recipe_name
FROM Recipes AS r
INNER JOIN Recipe_Ingredients AS ri
ON r.Recipe_ID = ri.Recipe_ID
INNER JOIN Ingredients AS i
ON ri.Ingredient_ID = i.Ingredient_ID
AND i.Ingredient_Name IN ('penne','onion')
AND r.Cooking_time < 60
GROUP BY r.Recipe_name HAVING rowcount = 2;
他们将获得包含 'penne' 和 'onion' 并在 60 分钟内完成烹饪的食谱。
我想不通的是如何按照下面的方式查询食谱;
- 包含 'penne' 和 'onion'
- 不包含'butter'
- 在 'less than 60 minutes'
中煮熟
我试过下面的代码,但它不起作用;
SELECT count(*) as rowcount, r.Recipe_name
FROM Recipes AS r
INNER JOIN Recipe_Ingredients AS ri
ON r.Recipe_ID = ri.Recipe_ID
INNER JOIN Ingredients AS i
ON ri.Ingredient_ID = i.Ingredient_ID
AND i.Ingredient_Name IN ('penne','onion')
AND i.Ingredient_Name NOT IN ('butter')
AND r.Cooking_time < 60
GROUP BY r.Recipe_name HAVING rowcount = 2;
非常感谢任何帮助!
谢谢。
在子查询中使用 NOT EXIST 子句:
NOT EXISTS(
SELECT 1 FROM Ingredients i
WHERE ri.Ingredient_ID = i.Ingredient_ID
AND i.Ingredient_Name IN ('butter')
)
完整查询:
SELECT count(*) as rowcount, r.Recipe_name
FROM Recipes AS r
INNER JOIN Recipe_Ingredients AS ri
ON r.Recipe_ID = ri.Recipe_ID
INNER JOIN Ingredients AS i
ON ri.Ingredient_ID = i.Ingredient_ID
AND i.Ingredient_Name IN ('penne','onion')
AND NOT EXISTS(
SELECT 1 FROM Ingredients i
WHERE ri.Ingredient_ID = i.Ingredient_ID
AND i.Ingredient_Name IN ('butter')
)
AND r.Cooking_time < 60
GROUP BY r.Recipe_name HAVING rowcount = 2;
您可以使用
SELECT r.Recipe_name,
r.Recipe_ID
FROM Recipes AS r
INNER JOIN Recipe_Ingredients AS ri
ON r.Recipe_ID = ri.Recipe_ID
INNER JOIN Ingredients AS i
ON ri.Ingredient_ID = i.Ingredient_ID
WHERE i.Ingredient_Name IN ( 'penne', 'onion', 'butter' )
AND r.Cooking_time < 60
GROUP BY r.Recipe_ID, /*<-- In case two recipes with same name*/
r.Recipe_name
HAVING
/*Must contain both these*/
COUNT(DISTINCT CASE
WHEN i.Ingredient_Name IN ( 'penne', 'onion' ) THEN i.Ingredient_Name
END) = 2
AND
/*Can't contain these*/
MAX(CASE
WHEN i.Ingredient_Name IN ( 'butter' ) THEN 1
ELSE 0
END) = 0
您也可以将 GROUP_CONCAT()
与 REGEXP
一起使用(好吧,可能不是最好的解决方案,但对于更复杂的查询可能没问题):
SELECT r.Recipe_Name
FROM Recipes r INNER JOIN Recipe_Ingredients ri
ON r.Recipe_ID = ri.Recipe_ID
INNER JOIN Ingredients i
ON ri.Ingredient_ID = i.Ingredient_ID
WHERE r.Cooking_Time <= 60
AND i.Ingredient_Name IN ('butter','onion','penne')
GROUP BY r.Recipe_Name
HAVING 'onion' REGEXP CONCAT('^(', GROUP_CONCAT(r.Ingredient_Name SEPARATOR '|'), ')$')
AND 'penne' REGEXP CONCAT('^(', GROUP_CONCAT(r.Ingredient_Name SEPARATOR '|'), ')$')
AND 'butter' NOT REGEXP CONCAT('^(', GROUP_CONCAT(r.Ingredient_Name SEPARATOR '|'), ')$');
我正在为用户可以查询的食谱网站做一个高级搜索功能;
- 食谱含有某些成分(最多 3 种成分)
- 食谱不含某些成分(最多 3 种成分)
- 在特定的烹饪时间下
以上几点可以在用户查询中结合在一起。
我已经完成了一半,我可以查询包含指定成分并在一定时间内烹制的食谱。
这是我的数据库结构;
Table:食谱
Recipe_ID、Recipe_Name、Cooking_time
Table:成分
Ingredient_ID、Ingredient_Name
Table: Recipe_Ingredients
食谱_Ingredient_ID、Ingredient_ID、Recipe_ID
这是我目前的 SQL 查询;
SELECT count(*) as rowcount, r.Recipe_name
FROM Recipes AS r
INNER JOIN Recipe_Ingredients AS ri
ON r.Recipe_ID = ri.Recipe_ID
INNER JOIN Ingredients AS i
ON ri.Ingredient_ID = i.Ingredient_ID
AND i.Ingredient_Name IN ('penne','onion')
AND r.Cooking_time < 60
GROUP BY r.Recipe_name HAVING rowcount = 2;
他们将获得包含 'penne' 和 'onion' 并在 60 分钟内完成烹饪的食谱。
我想不通的是如何按照下面的方式查询食谱;
- 包含 'penne' 和 'onion'
- 不包含'butter'
- 在 'less than 60 minutes' 中煮熟
我试过下面的代码,但它不起作用;
SELECT count(*) as rowcount, r.Recipe_name
FROM Recipes AS r
INNER JOIN Recipe_Ingredients AS ri
ON r.Recipe_ID = ri.Recipe_ID
INNER JOIN Ingredients AS i
ON ri.Ingredient_ID = i.Ingredient_ID
AND i.Ingredient_Name IN ('penne','onion')
AND i.Ingredient_Name NOT IN ('butter')
AND r.Cooking_time < 60
GROUP BY r.Recipe_name HAVING rowcount = 2;
非常感谢任何帮助!
谢谢。
在子查询中使用 NOT EXIST 子句:
NOT EXISTS(
SELECT 1 FROM Ingredients i
WHERE ri.Ingredient_ID = i.Ingredient_ID
AND i.Ingredient_Name IN ('butter')
)
完整查询:
SELECT count(*) as rowcount, r.Recipe_name
FROM Recipes AS r
INNER JOIN Recipe_Ingredients AS ri
ON r.Recipe_ID = ri.Recipe_ID
INNER JOIN Ingredients AS i
ON ri.Ingredient_ID = i.Ingredient_ID
AND i.Ingredient_Name IN ('penne','onion')
AND NOT EXISTS(
SELECT 1 FROM Ingredients i
WHERE ri.Ingredient_ID = i.Ingredient_ID
AND i.Ingredient_Name IN ('butter')
)
AND r.Cooking_time < 60
GROUP BY r.Recipe_name HAVING rowcount = 2;
您可以使用
SELECT r.Recipe_name,
r.Recipe_ID
FROM Recipes AS r
INNER JOIN Recipe_Ingredients AS ri
ON r.Recipe_ID = ri.Recipe_ID
INNER JOIN Ingredients AS i
ON ri.Ingredient_ID = i.Ingredient_ID
WHERE i.Ingredient_Name IN ( 'penne', 'onion', 'butter' )
AND r.Cooking_time < 60
GROUP BY r.Recipe_ID, /*<-- In case two recipes with same name*/
r.Recipe_name
HAVING
/*Must contain both these*/
COUNT(DISTINCT CASE
WHEN i.Ingredient_Name IN ( 'penne', 'onion' ) THEN i.Ingredient_Name
END) = 2
AND
/*Can't contain these*/
MAX(CASE
WHEN i.Ingredient_Name IN ( 'butter' ) THEN 1
ELSE 0
END) = 0
您也可以将 GROUP_CONCAT()
与 REGEXP
一起使用(好吧,可能不是最好的解决方案,但对于更复杂的查询可能没问题):
SELECT r.Recipe_Name
FROM Recipes r INNER JOIN Recipe_Ingredients ri
ON r.Recipe_ID = ri.Recipe_ID
INNER JOIN Ingredients i
ON ri.Ingredient_ID = i.Ingredient_ID
WHERE r.Cooking_Time <= 60
AND i.Ingredient_Name IN ('butter','onion','penne')
GROUP BY r.Recipe_Name
HAVING 'onion' REGEXP CONCAT('^(', GROUP_CONCAT(r.Ingredient_Name SEPARATOR '|'), ')$')
AND 'penne' REGEXP CONCAT('^(', GROUP_CONCAT(r.Ingredient_Name SEPARATOR '|'), ')$')
AND 'butter' NOT REGEXP CONCAT('^(', GROUP_CONCAT(r.Ingredient_Name SEPARATOR '|'), ')$');