唯一集的数据模型
Data model for unique sets
我正在寻找为 "recipes"
实现数据模型的最佳方法
像披萨应用一样思考,您可以在其中制作自己的披萨。您 select 可能 100 种成分中的 5 种,而您 select 每种成分的数量。我需要检查我之前是否 "seen" 那个披萨组合,如果没有则分配 ID,如果有则检索 ID。
我们有 n 种成分。
食谱由一组成分和相应的量定义。
可能看起来像:
Ingr1 90
Ingr2 10
或
Ingr1 90
Ingr2 10
Ingr3 10
我想将其存储在一个结构中,在该结构中我为每个唯一的食谱分配了一个 ID,这样我就可以在给定食谱数据集的情况下查询 ID。
我想要一个将数据集作为参数的存储过程,returns如果配方未知则为新 ID,如果配方已存在则为现有 ID。
我正在寻找最有效的方法。到目前为止,我最好的想法是要么将食谱编码为字符串 (json) 并将其用作唯一约束,要么使用一个存储过程来遍历食谱数据集并构建一个 n 级深度的 if exists 语句。
所以,我有信心我可以解决这个问题,但我正在寻找一个漂亮的方法。
据我所知,您有实体 Recipe 和 Ingredient 以及它们之间的 M:M 关系。数据模型可以如下所示(PK 以粗体显示):
食谱(食谱 ID,食谱名称)
成分(成分ID,成分名称)
RecipeIngredients(RecipeID, IngredientID, Amount)
您可以使用查询解决数据库中是否已存在相同配方的任务,但此查询并不简单。这是众所周知的问题,关系划分。有几种方法。最受欢迎的方法之一是数数。如果某个食谱的配料数量与目标食谱的配料数量相同,并且所有配料都相同,则它们是相等的。此类查询通常涉及数据聚合,并且在大量数据上执行速度不是很快。
您可以从应用程序方面帮助解决这个问题,并且您的思考方向是正确的。将配方表示为字符串,按 IngredientID 对值进行排序(即使以不同顺序添加成分也可以获得相同的字符串),以某种稳定的形式转换 Amount(不是获得 0.499999 而不是 0.5),从字符串中计算出一些哈希值,并存储食谱中的这个值。在简单形式中,hash 是一个整数值,因此您可以非常快速地找到双精度值。
所以这是你的电话。每种方法都有其自身的问题。在第一种情况下查询繁重,在第二种情况下很难将哈希保持在实际状态(也可能发生冲突)。我会坚持第一个选项,直到它工作正常,并且只有在不可避免时才开始任何优化。
查询示例(新配方在#tmp):
;with totals as
(
select RecipeID, count(*) totals
from RecipeIngredients
group by RecipeID
), matched_totals as
(
select i.RecipeID, count(*) matched_totals
from RecipeIngredients i
join #tmp t
on i.IngredientID = t.IngredientID
and i.Amount = t.Amount
group by i.RecipeID
)
select t.*
from totals t
join matched_totals m
on m.RecipeID = t.RecipeID
where
totals = matched_totals
and totals = (select count(*) from #tmp)
这个解决方案更优雅但更不直观:
select *
from Recipe r
where
not exists
( select 1
from RecipeIngredients ri
where
r.RecipeID = ri.RecipeID
and not exists
(select 1 from #tmp t where t.IngredientID = ri.IngredientID)
)
我正在寻找为 "recipes"
实现数据模型的最佳方法像披萨应用一样思考,您可以在其中制作自己的披萨。您 select 可能 100 种成分中的 5 种,而您 select 每种成分的数量。我需要检查我之前是否 "seen" 那个披萨组合,如果没有则分配 ID,如果有则检索 ID。
我们有 n 种成分。
食谱由一组成分和相应的量定义。
可能看起来像:
Ingr1 90
Ingr2 10
或
Ingr1 90
Ingr2 10
Ingr3 10
我想将其存储在一个结构中,在该结构中我为每个唯一的食谱分配了一个 ID,这样我就可以在给定食谱数据集的情况下查询 ID。
我想要一个将数据集作为参数的存储过程,returns如果配方未知则为新 ID,如果配方已存在则为现有 ID。
我正在寻找最有效的方法。到目前为止,我最好的想法是要么将食谱编码为字符串 (json) 并将其用作唯一约束,要么使用一个存储过程来遍历食谱数据集并构建一个 n 级深度的 if exists 语句。
所以,我有信心我可以解决这个问题,但我正在寻找一个漂亮的方法。
据我所知,您有实体 Recipe 和 Ingredient 以及它们之间的 M:M 关系。数据模型可以如下所示(PK 以粗体显示):
食谱(食谱 ID,食谱名称)
成分(成分ID,成分名称)
RecipeIngredients(RecipeID, IngredientID, Amount)
您可以使用查询解决数据库中是否已存在相同配方的任务,但此查询并不简单。这是众所周知的问题,关系划分。有几种方法。最受欢迎的方法之一是数数。如果某个食谱的配料数量与目标食谱的配料数量相同,并且所有配料都相同,则它们是相等的。此类查询通常涉及数据聚合,并且在大量数据上执行速度不是很快。
您可以从应用程序方面帮助解决这个问题,并且您的思考方向是正确的。将配方表示为字符串,按 IngredientID 对值进行排序(即使以不同顺序添加成分也可以获得相同的字符串),以某种稳定的形式转换 Amount(不是获得 0.499999 而不是 0.5),从字符串中计算出一些哈希值,并存储食谱中的这个值。在简单形式中,hash 是一个整数值,因此您可以非常快速地找到双精度值。
所以这是你的电话。每种方法都有其自身的问题。在第一种情况下查询繁重,在第二种情况下很难将哈希保持在实际状态(也可能发生冲突)。我会坚持第一个选项,直到它工作正常,并且只有在不可避免时才开始任何优化。
查询示例(新配方在#tmp):
;with totals as
(
select RecipeID, count(*) totals
from RecipeIngredients
group by RecipeID
), matched_totals as
(
select i.RecipeID, count(*) matched_totals
from RecipeIngredients i
join #tmp t
on i.IngredientID = t.IngredientID
and i.Amount = t.Amount
group by i.RecipeID
)
select t.*
from totals t
join matched_totals m
on m.RecipeID = t.RecipeID
where
totals = matched_totals
and totals = (select count(*) from #tmp)
这个解决方案更优雅但更不直观:
select *
from Recipe r
where
not exists
( select 1
from RecipeIngredients ri
where
r.RecipeID = ri.RecipeID
and not exists
(select 1 from #tmp t where t.IngredientID = ri.IngredientID)
)