SQL多table复合键唯一查询
SQL multi-table composite key unique query
首先,一些背景信息。我正在构建一个简单的食谱书数据库,并且我正在尝试构建一个查询,该查询将显示我可以根据食品储藏室中的物品制作什么。 table 模式如下:
RECIPE(*RecipeID*, RecipeName)
RECIPE_INGREDIENT(***RecipeID***, **IngredientID**)
INGREDIENT(*IngredientID*, IngredientName)
PANTRY_ITEM(*ItemID*, ItemName)
RECIPE_INGREDIENT table 中的字段构成一个组合键,并且都是 RECIPE(RecipeID) 和 INGREDIENT(IngredientID) table 的外键。我正在使用以下测试数据:
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'
所以基本上我是在尝试根据我储藏室中的物品查询 RecipeNames 列表。通过这个,我的意思是我的储藏室里必须有食谱的所有成分,才能将它添加到列表中。因此,基于此测试数据的理想查询只会产生 'food 2'。我 运行 遇到的问题是对配方部分执行 'all ingredients'。
我尝试了几个不同的查询,它们都会返回每个食谱。
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)))
有没有人知道我如何才能做到这一点?是否有可能对此进行查询,或者我是否必须重组我的数据库?
这不会很好地执行,但可以在不更改架构的情况下实现。不过我建议,也许你应该考虑让你的 PANTRY table 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
);
首先,如果您可以将 仅 成分放入储藏室,您的 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演示
这是你的答案
select r1.recipeName from recipe r1 where r1.recipeName not in
(
select r.recipeName from recipe r
inner join
recipe_ingredient ri
on r.recipeid=ri.RecipeID
inner JOIN
ingredient i
on ri.IngredientID=i.ingredientid and
i.IngredientName not in (select itemname from pantry_item) )
实际上,我不明白为什么您需要的不仅仅是两个 table。您的食谱 table 还需要两个字段。计量单位(茶匙、杯、盎司等)以及配方需要多少计量单位。成分 table 需要相同的两个字段,只是这是储藏室中可用的数量。您需要其他计量单位,因为食谱可能需要一杯糖,但您按磅购买糖。
您还需要一个 udf 来从一个单位转换为另一个单位,所以如果食谱需要 2 茶匙香草,而食品储藏室显示还剩 1 盎司,够了吗?
然后只需在食谱和配料之间执行外部连接,并忽略那些含有任何空配料的配料(食品储藏室中没有或配料不足)。
首先,一些背景信息。我正在构建一个简单的食谱书数据库,并且我正在尝试构建一个查询,该查询将显示我可以根据食品储藏室中的物品制作什么。 table 模式如下:
RECIPE(*RecipeID*, RecipeName)
RECIPE_INGREDIENT(***RecipeID***, **IngredientID**)
INGREDIENT(*IngredientID*, IngredientName)
PANTRY_ITEM(*ItemID*, ItemName)
RECIPE_INGREDIENT table 中的字段构成一个组合键,并且都是 RECIPE(RecipeID) 和 INGREDIENT(IngredientID) table 的外键。我正在使用以下测试数据:
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'
所以基本上我是在尝试根据我储藏室中的物品查询 RecipeNames 列表。通过这个,我的意思是我的储藏室里必须有食谱的所有成分,才能将它添加到列表中。因此,基于此测试数据的理想查询只会产生 'food 2'。我 运行 遇到的问题是对配方部分执行 'all ingredients'。
我尝试了几个不同的查询,它们都会返回每个食谱。
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)))
有没有人知道我如何才能做到这一点?是否有可能对此进行查询,或者我是否必须重组我的数据库?
这不会很好地执行,但可以在不更改架构的情况下实现。不过我建议,也许你应该考虑让你的 PANTRY table 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
);
首先,如果您可以将 仅 成分放入储藏室,您的 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演示
这是你的答案
select r1.recipeName from recipe r1 where r1.recipeName not in
(
select r.recipeName from recipe r
inner join
recipe_ingredient ri
on r.recipeid=ri.RecipeID
inner JOIN
ingredient i
on ri.IngredientID=i.ingredientid and
i.IngredientName not in (select itemname from pantry_item) )
实际上,我不明白为什么您需要的不仅仅是两个 table。您的食谱 table 还需要两个字段。计量单位(茶匙、杯、盎司等)以及配方需要多少计量单位。成分 table 需要相同的两个字段,只是这是储藏室中可用的数量。您需要其他计量单位,因为食谱可能需要一杯糖,但您按磅购买糖。
您还需要一个 udf 来从一个单位转换为另一个单位,所以如果食谱需要 2 茶匙香草,而食品储藏室显示还剩 1 盎司,够了吗?
然后只需在食谱和配料之间执行外部连接,并忽略那些含有任何空配料的配料(食品储藏室中没有或配料不足)。