我应该找到正确的MySQL查询还是优化数据库结构?

时间:2016-12-12 18:04:42

标签: mysql

我有以下结构的数据库:

  • 表成分(成分名称,颜色)

  • TABLE食谱(recipe_name)

  • 表recipes_ingredients_parts(recipe_name,ingredient_name,parts)

我想要的是获得与所选成分及其数量相对应的配方。所以我首先尝试的是查询:

SELECT rr.* FROM 
  (SELECT r.* FROM receipes r 
    INNER JOIN receipes_ingredients_parts ri 
      ON r.receipe_name = ri.receipe_name 
        AND ri.ingredient_name = 'espresso' 
        AND ri.parts_number = '1') rr;

我得到的是{" Americano"," Espresso"}。但那应该是#34; Espresso"只是因为" Americano"应该有查询:

SELECT rr.* FROM 
 (SELECT r.* FROM receipes r 
   INNER JOIN receipes_ingredients_parts ri 
     ON r.receipe_name = ri.receipe_name 
       AND ri.ingredient_name = 'espresso' 
       AND ri.parts_number = '1') rr 
   INNER JOIN receipes_ingredients_parts ri 
     ON rr.receipe_name = ri.receipe_name 
       AND ri.ingredient_name = 'water' 
       AND ri.parts_number = '4';

接下来我的想法是改变配方表并为每种配料添加列以存储配方的数量。但它将近20列。因此,我对自己以糟糕的方式做工作的想法感到困惑。也许我应该为此目的使用一些好的查询?你们对这些东西有什么想法吗?

1 个答案:

答案 0 :(得分:1)

我认为这正是您所寻找的,它应该找到包含您列表中所有成分的receipe_names,而不是其他成分。

SELECT receipe_name
, SUM(CASE 
      WHEN (ingredient_name, parts_number) IN (('espresso','1')) 
      THEN 1 ELSE 0 
      END
) AS matchedIngredients
, SUM(CASE 
      WHEN (ingredient_name, parts_number) NOT IN (('espresso','1')) 
      THEN 1 ELSE 0 
      END
) AS otherIngredients
FROM receipes_ingredients_parts
GROUP BY receipe_name 
HAVING matchedIngredients = 1 AND otherIngredients = 0

更通用的版本/模板:

SELECT aField
, SUM(CASE 
      WHEN someField IN ([matchList]) 
      THEN 1 
      ELSE 0 
      END
) AS matches
, SUM(CASE 
      WHEN someField NOT IN ([matchList]) 
      THEN 1 
      ELSE 0 
      END
) AS others
FROM aTable
GROUP BY aField
HAVING matches = [# of values in matchlist] 
   AND others = 0

或者,如果匹配列表中的项目可能会在表格中重复,并且#34; aField"值:

SELECT aField
, COUNT(DISTINCT CASE 
      WHEN someField IN ([matchList]) 
      THEN someField
      ELSE NULL
      END
) AS matches
, COUNT(DISTINCT CASE 
      WHEN someField NOT IN ([matchList]) 
      THEN someField 
      ELSE NULL
      END
) AS others
FROM aTable
GROUP BY aField
HAVING matches = [# of values in matchlist] 
   AND others = 0