【问题标题】:SQL query recipes with these ingredient(s) but NOT these ingredient(s)具有这些成分的 SQL 查询食谱)但不是这些成分)
【发布时间】:2015-01-18 13:02:56
【问题描述】:

我正在为用户可以查询的食谱网站提供高级搜索功能;

  • 配方具有某些成分(最多 3 种成分)的存在
  • 配方没有某些成分的存在(最多 3 种成分)
  • 在特定烹饪时间下

上述几点可以在用户查询中组合在一起。

我已经完成了一半,我可以查询包含指定成分并在一定时间内烹制的食谱。

这是我的数据库结构;

表格:食谱

Recipe_ID、Recipe_Name、Cooking_time

表格:成分

Ingredient_ID、Ingredient_Name

表格:Recipe_Ingredients

Recipe_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;

将获得包含“通心粉”和“洋葱”并在 60 分钟内煮熟的食谱。

我想不通的是如何按以下方式查询食谱;

  • 包含“通心粉”和“洋葱”
  • 不含“黄油”
  • 在“不到 60 分钟”内完成

我尝试了下面的代码,但它不起作用;

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;

非常感谢任何帮助!

谢谢。

【问题讨论】:

    标签: mysql sql relational-division


    【解决方案1】:

    你可以使用

    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 
    

    【讨论】:

      【解决方案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;
      

      【讨论】:

        【解决方案3】:

        您也可以将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 '|'), ')$');
        

        See SQL Fiddle demo 在这里。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-04-04
          • 1970-01-01
          • 2016-05-21
          • 2011-03-02
          • 2021-02-18
          • 1970-01-01
          相关资源
          最近更新 更多