SQL多表复合键唯一查询

时间:2015-05-15 03:56:40

标签: mysql sql database composite

首先,一些背景信息。我正在构建一个简单的食谱书数据库,我正在尝试构建一个查询,根据我的食品室中的项目向我展示我可以制作的内容。表模式如下:

RECIPE(*RecipeID*, RecipeName)
RECIPE_INGREDIENT(***RecipeID***, **IngredientID**)
INGREDIENT(*IngredientID*, IngredientName)
PANTRY_ITEM(*ItemID*, ItemName)

RECIPE_INGREDIENT表中的字段组成一个复合键,并且都是RECIPE(RecipeID)和INGREDIENT(IngredientID)表中的外键。我使用以下测试数据:

RECIPE table
RecipeID,RecipeName
1,'food 1'
2,'food 2'

INGREDIENT Table
IngredientID, IngredientName
1,'ing 1'
2,'ing 2'
3,'ing 3'

RECIPE_INGREDIENT table
RecipeID,IngredientID
1,1
1,2
2,2
2,3

PANTRY_ITEM table
ItemID,ItemName
1,'ing 2'
2,'ing 3'

所以基本上我试图根据我在食品室里的物品来查询食谱名单。通过这个,我的意思是我必须在我的食品室里有食谱的所有成分,以便将它添加到列表中。因此,基于该测试数据的理想查询将仅导致食物2'。我遇到的问题是强制执行所有成分'对于食谱部分。

我尝试了几个不同的查询,它们都会导致每个食谱都被退回。

SELECT RecipeName FROM RECIPE WHERE RecipeID IN (SELECT RecipeID FROM RECIPE_INGREDIENT WHERE IngredientID IN (SELECT IngredientID FROM INGREDIENT WHERE IngredientName IN (SELECT ItemName FROM PANTRY_ITEM)))

有没有人对如何实现这一点有任何想法?是否有可能的查询,或者我是否需要重构我的数据库?

4 个答案:

答案 0 :(得分:1)

首先,如果您可以将成分放入食品储藏室,那么pantry架构应该看起来像这样

CREATE TABLE pantry
(
  IngredientID int,
  FOREIGN KEY (IngredientID) REFERENCES ingredient (IngredientID)
);

现在,您可以利用HAVING子句获得所需的结果

SELECT recipename
  FROM
(
  SELECT recipeid
    FROM recipe_ingredient ri LEFT JOIN pantry p
      ON ri.ingredientid = p.ingredientid
   GROUP BY recipeid
   HAVING COUNT(*) = COUNT(p.ingredientid)
) q JOIN recipe r
    ON q.recipeid = r.recipeid

输出:

| RecipeName |
|------------|
|     food 2 |

这是 SQLFiddle 演示

答案 1 :(得分:0)

这不会很好,但可以在不改变架构的情况下实现。我建议,或许你应该考虑让你的PANTRY表id与成分id匹配......

基本上,我们必须在将食谱成分与其食品等效物品进行比较时,随时找到一个NULL值。子查询中的任何NULL实例都意味着缺少项目......所以我们只生成一个排除列表并将结果与​​之比较。

SELECT RecipeID AS _id, RecipeName FROM RECIPE WHERE RecipeID NOT IN (
  SELECT d.RecipeId FROM (
    SELECT p.ItemID, r.RecipeID FROM PANTRY_ITEM p
      JOIN INGREDIENT i ON (p.ItemName = i.IngredientName)
      RIGHT JOIN RECIPE_INGREDIENT ri ON (ri.IngredientId = i.IngredientId)
      RIGHT JOIN RECIPE r ON (r.RecipeId = ri.RecipeId)
  ) d WHERE d.ItemID IS NULL
);

答案 2 :(得分:0)

这是你的答案

angular('appName').directive('itemDirective',function(){
            return{
            restrict:'E',
            replace:true,
            templateUrl:'item.view.html',
            scope:{
                data:'='
            },
            controller:function($scope,$log){
                 $scope.clickMe=function(){
                    $log.debug('clicked!', $scope.data.name);
                 }
            }
        };
});

答案 3 :(得分:0)

实际上,我不明白为什么你需要的不仅仅是两张桌子。您的食谱表还需要两个字段。一个测量单位(茶匙,杯子,盎司等)以及配方需要多少测量。成分表只需要相同的两个字段,这就是食品室中可用的数量。你需要另一个测量单位,因为食谱可能需要一杯糖,但你可以用英镑购买糖。

你还需要一个udf来从一个单位转换成另一个单位,所以如果食谱需要2茶匙香草,而食品室剩下1盎司,那还够吗?

然后只需在食谱和配料之间进行外部连接,并忽略那些含有任何零成分的食物(食物中没有或没有足够的成分)。