建模层次属性

dex*_*ter 5 tree database-design hierarchy

我正在尝试找出零售商的数据模型。

该零售商在全国拥有多家商店,它们使用以下层次结构进行建模:

Channel -> Zone -> City -> Store
Run Code Online (Sandbox Code Playgroud)

每家商店都包含几篇文章。每篇文章都有这样的属性

  • 激活标志(这表明文章的存在)
  • 价钱
  • 供应商
  • 仓库

现在,零售商可以在层次结构中的任何级别设置这些属性。考虑以下情况:

  • 在渠道级别为商品设置价格将应用于所有商店。
  • 设置在更高级别的价格可以在任何其他级别被覆盖。例如,在城市级别仅针对城市中的商店或特定商店。
  • 这适用于上面列出的所有属性。

到目前为止,他们已经使用 RDBMS 对其进行建模,方法是在层次结构的顶部定义全局规则,并将异常作为单独的行单独调用。比如说,价格表将在渠道级别为文章设置价格,任何级别的任何更改都将单独指定。显然,这在获取商店级别的属性时效率不高。

样本数据

假设 Channel、Zone、City 和 Store 统称为实体。频道的 ID 范围 >= 4000,区域 >= 3000,城市 >= 2000,商店范围从 1 到 1000。

下面给出了层次关系数据的一个子集:

Channel   | Zone     | City    | Store |
----------+----------+------------------
4001      | 3001     | 2001    | 13    |
4001      | 3001     | 2001    | 14    |
4001      | 3001     | 2002    | 15    |
4001      | 3002     | 2003    | 16    |
4001      | 3003     | 2006    | 74    |
Run Code Online (Sandbox Code Playgroud)

价格表

ArticleID | EntityID | Price
----------+----------+----------
12345     | 4001     | 2.5
12345     | 2003     | 2.9
12345     | 74       | 3.0
Run Code Online (Sandbox Code Playgroud)

在这里,所有商店中的商品将设置频道 4001 的价格 2.5。接下来的两行设置了一些商店的价格例外。2003年城市设置的第二个价格2.9只适用于店铺16中的商品,按照上面提到的层级关系。第三行直接设置74店铺商品的价格3.0。

希望这可以让您了解当前的模型。那么,你能建议一个更好的方法来存储它吗?

Joe*_*own 5

您可以将您已经在使用的方法形式化,并使其更有效地维护和查询。考虑这样的 ERD:

ERD

请注意,您的所有层次结构都被展平为一组列。存在内卷关系,因此层次结构中的每个子实体都可以指向它的直接父实体。我还包括了左右访问次数,这将真正帮助您进行价格查询。最后有一Level列用于存储层次结构中的排名。

如果您不熟悉访问次数,请查看我对这个问题的回答,我会在其中详细介绍。

那么为什么这比你现在做的更好呢?

  1. 您只需跟踪层次结构中的每个项目一次。与 4001 多次出现在频道列中不同,您只有一个 4001 的记录。

  2. 该结构是灵活的,并允许在以后插入新的级别。它还允许不均匀的树木,例如,ZONE 3001 被细分为三个 SUBZONE,并且城市在那里的子区域之下(但直接到 3001 之外的区域)。

  3. 您所有的价格都在一个地方(它不需要任何超出正常 SQL 查询的读取逻辑。您不必根据 EntityID 所在的范围将价格连接到不同的实体表中,而是有一个一致的价格检索查询。

  4. 您不需要标识符中的编码含义,因此当您在任何一级获得太多实体时不会遇到麻烦,从而破坏您的编码方案。

  5. 价格检索查询非常简单:


-- Look up the left and right numbers for the store in question:
declare @StoreLeft int
declare @StoreRight int
select @StoreLeft = H.left, @StoreRight = H.right
from HIERARCHY H where H.ID = @DesiredStoreId

-- Look up the lowest level (most granular) price for this store:
select TOP 1
  P.price_amt
, P.currency
from PRICE P
  inner join HIERARCHY H
    on H.Left <= @StoreLeft and H.right >= @StoreRight
  inner join ARTICLE A
    on P.article_id = A.id
where A.id = @TheArticleInQuestion
order by H.Level ASC   -- ASC or DESC depends on how you count levels.
Run Code Online (Sandbox Code Playgroud)