我有一个名为“食谱”的表格,以名为“成分”的 SET 类型列出了食谱中使用的所有食物(食谱仅限于使用少量特定成分)。
食谱表
id(整数)
菜谱名称(文本)
成分(套装)
我有另一个名为“food_types”的表。每条记录都有一个“名称”字段(例如“水果”、“家禽”、“香料”、“肉类”……)和一个名为“项目”的 SET 类型,其中包含属于该食品类型的成分。例如。对于“水果”记录,SET 可能是“苹果、橙子、梨、香蕉”。 '
食物类型表
id(整数)
类别(文本)
项目(设置)
我的问题是如何创建一个 MySQL 查询,该查询从“食谱”表中选择所有记录,该表包含“成分”集中给定“项目”集中的一项或多项。
所以用英语我的查询可能是:
“选择成分包含一种或多种水果的所有食谱”
谁能建议一个使用 MySQL 查询来做到这一点的好方法?
注意:我很欣赏有更好的方法来构建食谱/配料问题的表,但我正在寻找一种 MySQL 查询解决方案,可以使用 SET 和上述表来实现此目的。
最佳答案
这是对 SET 字段的不当使用 - 您无法在不进行模式修改的情况下添加 food_type,这始终是您的结构错误的一个很好的指示。使用连接表来表示多对多关系。在本例中,创建一个表 ingredient_type
,它引用具有 ingredient_id
和 food_type_id
的两个表。这还允许您拥有多种类型的成分,就像 SET 一样,但更加灵活。
ingredient (ingredient):
apple
orange
chicken
ginger
potato
food_type (type):
fruit
vegetable
meat
poultry
spice
ingredient_type (ingredient, type)
apple, fruit
orange, fruit
chicken, meat
chicken, poultry
ginger, vegetable
ginger, spice
potato, vegetable
recipe_ingredient (recipe, ingredient):
recipe1, chicken
recipe1, potato
recipe2, orange
recipe2, ginger
使用该结构,您可以执行如下查询:
SELECT DISTINCT(recipe) FROM recipe_ingredient WHERE ingredient = 'orange';
这将向您展示所有使用橙子的食谱。稍微复杂一点:
SELECT DISTINCT(recipe) FROM recipe_ingredient JOIN ingredient_type on recipe_ingredient.ingredient = ingredient_type.ingredient WHERE ingredient_type.type = 'fruit';
这将找到所有使用水果成分的食谱。
编辑:关于使用 SET。
您可以通过利用 SET 存储的二进制性质来做到这一点。如果配方成分和类别成员之间存在重叠,则按位 AND(使用 &
运算符)中设置的位数将 > 0:
SELECT DISTINCT recipeName FROM recipes JOIN food_types ON BIT_COUNT(food_types.items & recipes.ingredients) > 0 WHERE food_types.category = 'fruit';
只有当成分和元素集定义完全相同时,这才有效。
SET 还存在其他问题:
- 它们最多只能包含 64 项
- 字段值的顺序始终与集合的顺序相同
- 除简单匹配之外的大多数查询(例如匹配集合中的单个项目)都不会被索引
- 除非定义相同,否则 SET 无法进行比较
- 没有地方可以放置有关每个项目的附加元数据
这种方法违背了使用关系数据库的大部分要点。这是教科书上的第一范式数据库内容。我认为这样的结构的唯一目的是用作如何不这样做的示例。
关于MySQL如何使用SET类型来选择一个SET包含另一个SET中的一个或多个项目的记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26733162/