唯一集的数据模型

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)
    )