【问题标题】:mysql select having multiple n to n'smysql select有多个n到n
【发布时间】:2011-08-22 12:38:26
【问题描述】:

我有类似这样的表格

recipes_tbl
| id | Recipe | Directions |

ingredients_tbl
| id | Ingrediant | Category |

recipe_to_ingredient
| id | id_recipe  | id_ingredient | Quantity

我正在尝试构建一个查询以“获取所有使用牛肉(id_ingredient 1) 和土豆(id_ingredient 2) 和 ...n 的食谱”

我怀疑解决方案涉及某种花哨的连接...也许?

【问题讨论】:

    标签: mysql


    【解决方案1】:
    SELECT     R.ID, R.Recipe, R.Directions
    FROM       Ingredients_tbl I
               INNER JOIN recipe_to_ingredient RI ON I.id = RI.id_ingredient 
               INNER JOIN recipes_tbl R ON R.id = R.id_recipe  
    WHERE      I.ID IN (1 ,2)
    GROUP BY   R.ID, R.Recipe, R.Directions
    HAVING     COUNT(*) > 1
    

    应该这样做,尽管此示例中的成分被硬编码为只有 1 或 2。我需要了解更多关于您打算如何提供成分 ID 以在这方面提供更多信息。

    【讨论】:

    • 应该JOIN recipes_tbl R ON I.id = R.id_recipeJOIN recipes_tbl R ON R.id = RI.id_recipe
    • 当我在 WHERE 子句中使用超过 2 个值时,HAVING 子句中的数字应该是 -1 吗?
    • 是的,感谢 unutbu 的拼写错误。是的,马特,如果你有 3 个项目,它会是 2,4 会是 3 等等。正如你所说的 HAVING COUNT(*) > (n-1)。
    • @Steve:你可以使用COUNT(*)=n :)
    【解决方案2】:

    使用 EXISTS

    SELECT 
        id, Recipe, Directions
    FROM
        recipes_tbl AS r
    WHERE EXISTS 
            ( SELECT *
              FROM recipe_to_ingredient AS ri
                JOIN ingredients_tbl AS i
                  ON i.id = ri.id_ingredient
              WHERE ri.id_recipe = r.id
                AND i.Ingredient = 'beef'
           )
      AND EXISTS 
            ( SELECT *
              FROM recipe_to_ingredient AS ri
                JOIN ingredients_tbl AS i
                  ON i.id = ri.id_ingredient
              WHERE ri.id_recipe = r.id
                AND i.Ingredient = 'potatoes'
           )
      ...
    

    使用 JOIN

    SELECT 
        r.id, r.Recipe, r.Directions
    FROM
        recipes_tbl AS r
      JOIN 
        recipe_to_ingredient AS ri1
          ON ri1.id_recipe = r.id
      JOIN
        ingredients_tbl AS i1
          ON i1.id = ri1.id_ingredient
          AND i1.Ingredient = 'beef'
      JOIN 
        recipe_to_ingredient AS ri2
          ON ri2.id_recipe = r.id
      JOIN
        ingredients_tbl AS i2
          ON i2.id = ri1.id_ingredient
          AND i2.Ingredient = 'potatoes'
      ...
    

    使用 GROUP BY

    SELECT 
        r.id, r.Recipe, r.Directions
    FROM
        recipes_tbl AS r
      JOIN 
        recipe_to_ingredient AS ri
          ON ri.id_recipe = r.id
      JOIN
        ingredients_tbl AS i
          ON i.id = ri.id_ingredient
    WHERE i.Ingredient IN ('beef', 'potatoes', ...)
    GROUP BY r.id
    HAVING COUNT(*) = @n              --- number of items in above list 
    

    如果您已经有了成分的 ID,则无需加入 ingredients 表(在所有 3 个版本中)。

    GROUP BY 解决方案的优势在于,您可以更改它以显示具有例如 “至少 5 种,共 7 种成分”的食谱,只需将 HAVING COUNT(*)=7 更改为 @ 987654330@。其他两种方式在这方面并不灵活。

    但它们可能会更快,具体取决于您的表的大小、分布和您运行的查询(使用 2、3 或 20 种成分?)

    【讨论】:

    • 这些方法中的任何一种都比其他方法更有效吗?
    • 正如我上一条评论所暗示的,您需要使用您的数据(和查询详细信息)进行测试。当您搜索 2 和 20 种成分时,您可能会看到不同的结果(关于速度)。
    【解决方案3】:
    SELECT     R.ID, R.Recipe, R.Directions
    FROM       recipes_tbl R
    WHERE      R.ID IN (SELECT id_recipe 
                        FROM   recipe_to_ingredient RI
                        INNER JOIN Ingredient I ON I.id = RI.id_ingredient
                        WHERE I.Ingredient in ('Beef','Potato'))
    

    【讨论】:

      【解决方案4】:

      已编辑:

      试试这个查询 -

      SELECT
        r.Recipe
      FROM
        recipes_tbl r
      JOIN recipe_to_ingredient r_i
        ON r.id = r_i.id_recipe
      JOIN ingredients_tbl i
        ON i.id = r_i.id_ingredient
      GROUP BY
        r.Recipe
      HAVING
        COUNT(IF(i.Ingrediant = 'beef', 1, 0)) > 0
        AND
        COUNT(IF(i.Ingrediant = 'potatoes', 1, 0)) > 0
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-29
        • 1970-01-01
        相关资源
        最近更新 更多