【问题标题】:Database Design: how to model generic price factors of a product/service?数据库设计:如何为产品/服务的通用价格因素建模?
【发布时间】:2011-03-02 22:39:31
【问题描述】:

我正在尝试创建一个通用数据模型,该模型将允许特定产品(由下表中的 FK product_id 指示)指定 0 个或多个价格“因素”(我将“因素”定义为一个单位为了得到总数而增加或减少的价格)。

所以说有这张桌子:

===============================
price
===============================
price_id (PK)
product_id (FK)
label
operation (ENUM: add, subtract)
type (ENUM: amount, percentage)
value

一本书的价格可以这样表示:

====================================================================
price_id | product_id | label      |  operation | type       | value
====================================================================
 1       | 10         | Price      | add        | amount     | 20  
 2       | 10         | Discount   | subtract   | percentage | .25  
 3       | 10         | Sales Tax  | add        | percentage | .1

这基本上意味着:

Price:      $20.00
Discount:  - $5.00 (25%)
--------------------
Sub Total:  $15.00
Sales Tax:   $1.50 (10%)
------------------------
Total:      $16.50

几个问题:

  1. 最初的设计有什么明显的问题吗?
  2. 如果我想创建“模板”(例如,具有“价格”、“折扣”和“销售税”字段的“普通商品”模板;具有“价格”、“折扣”的“奢侈品”, “奢侈税”字段)- 我将如何建模?
  3. 如果每条记录适用于前面记录的总数,则上述模型有效。因此,在示例中,“销售税”适用于“价格”和“折扣”的差异。如果总的计算不是那么简单呢?例如:A + B + (A + 10%) - (B - 5%)。我将如何建模?
  4. 此外,如果“百分比”类型不适用于紧接在前的行(如问题 #3 所暗示的那样)并应用于超过 1 行,该怎么办?我是否需要另一个表格来逐项列出百分比适用的价格->price_id?

【问题讨论】:

  • +1 获取完整的图表、示例数据和示例!我希望所有数据库问题都像这样完整。
  • 是的,但如果表格包含 Karl 的回答中所示的序列列会更好);)

标签: mysql database database-design


【解决方案1】:

关于您的问题 1

labeloperationtype 之间存在潜在的函数依赖关系。例如,折扣可能总是暗示减法百分比。如果是这样,可以通过将这些字段移动到单独的表中来规范化数据模型,并将 label 作为 PK。

顺便说一句,去规范化的数据模型可能是提高性能和/或简单性的合法工具。

关于您的问题 2

这是一个允许简单“模板化”的模型:

产品的最终价格是通过对 PRICE 应用一系列步骤来计算的,顺序由 STEP_NO 定义。多个产品可以轻松共享同一个“模板”(即同一个 PRICE_ADJUSTMENT_ID)。

关于您的问题 3 和 4

您需要为完整的表达式树建模,而不仅仅是“线性”一系列步骤。有几种方法可以做到这一点,其中大多数在关系范式中相当复杂。也许最简单的一种是保持与上面类似的数据模型,但将其视为Reverse Polish Notation

例如...

A + B + (A + 10%) - (B - 5%)

...可以表示为:

OPERATION    TYPE       VALUE
----         ----       -----
             value      A
             value      B
add
             value      A
             percentage 10
add
add
             value      B
             percentage 5
subtract
subtract

你确定你真的需要这种功能吗?

【讨论】:

    【解决方案2】:

    首先你需要一个价格标签模型,很简单:

    price_labels
     id | label 
      1 | Price 
      2 | Discount 
      3 | Tax
    

    然后是您给出的示例表的略微修改版本:

    products_prices
    price_id|product_id|label_id|divider|value 
      1         10        1        1      20 
      2         10        2        100   -25 
      3         10        3        100    10 
    

    这里我只是将标签替换为 price_labels 表中对应的 id 作为外键。此外,我省略了 type 字段,因为值可以是正浮点数或负浮点数,所以它是微不足道的。我添加了分隔栏以启用百分比参数。我认为以这种方式阅读也更容易,因为您说(并认为)“减去百分之二十五”而不是 0.25 。

    现在“抽象”部分的表达有点复杂,可能有很多解决方案。

    price_expressions
    product_id | date_from          | date_until          | expression
      10       |2011-11-02 04:00:00 |2011-11-12 04:00:00  | (SELECT divider*value from 
                                                             products_prices 
                                                             WHERE product_id=%PRODUCT_ID%    
                                                             AND label_id=1)*
                                                            (SELECT 1+value/divider from products_prices 
                                                             where product_id=%PRODUCT_ID% AND 
                                                             label_id=2)*
                                                            (SELECT 1+value/divider from products_prices 
                                                             where product_id=%PRODUCT_ID% AND                                  
                                                             label_id=3)
    

    在表达式字段中,您可以存储一个复杂的 SQL 语句,您可以在其中将 %PRODUCT_ID% 占位符替换为同一行中的 product_id 值:

    SELECT REPLACE(expression,'%PRODUCT_ID%',CAST(product_id AS char)) 
    AS price_expression FROM price_expressions 
    WHERE product_id = 10 AND date_from>=DATE_OF_PURCHASE 
    AND date_until<=DATE_OF_PURCHASE
    

    在我看来,这有两种可能的变化:

    1. 您可以仅使用 price_id=N 更改 product_id=%PRODUCT_ID% 和 label_id=N 条件,因为您已经将其存储在 products_prices 表中
    2. 您可以使用其他表达式格式,例如%PRICE_ID_1%*%PRICE_ID_2 并在应用程序级别执行替换和计算,而不是直接在 SQL 中

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      这似乎有点过度设计。

      1) 销售税百分比是否会影响商品的购买地点而不是购买的商品?我可以看到“IsTaxable”字段,但指定每个项目的税率似乎不正确。

      2) 你确定你需要承担制作这个通用的成本吗?您是否已经相当确定未来会有更多的因素?如果没有,请不要过于复杂。

      建议设计
      - 为 IsTaxable、DiscountPct 和 Unit Price 添加列到产品表中。
      - 将销售税百分比存储在另一个表中。可能是发票表。

      【讨论】:

      • 销售税不仅在地域上确定。实际项目也很重要。例如,某些产品除销售税外还要征收罪恶/罪恶税。此外,这不仅仅是税收。我关心任何价格因素。例如,新车和二手车有很长的价格因素清单(例如基本价格、目的地费用、选项等)。由于无法知道所有这些可能的价格因素是什么,我希望用户能够定义它们。
      • 在新西兰,销售税 (GST) 是任何销售额的 15%。简单易建模。在澳大利亚,它会根据产品类型而有所不同(或至少习惯于 - 我不需要保持最新状态)。例如,面包是 X% 的马厩,但面包卷可能是 Y% 的奢侈品。然后如果你想低头,试试英国惨败......
      • 去德国,销售税有时也取决于邮政编码(某些邮政编码免征销售税);)
      • 核心价格与所有价格因素不同,因此不应将它们一起存储在同一个表中。应用价格因素的规则与创建它们的法律一样复杂。但基本上有两种类型:您施加的(例如分级定价)与外部施加的。通常您的价格是第一位的,通常所有其他价格仅适用于您的售价,通常不适用于运费和人工。
      【解决方案4】:

      如果某些价格因素取决于项目的类型,那么您将有一组价格因素链接到 ItemType 表中的实体,并且 ItemType 将是项目实体的属性(引用 ItemType 的外键) .如果其他价格因素与商品销售或运输的地区相关联(例如销售税),那么这些因素将与地区相关联,并根据客户的地址调用。您通常会在行项目级别应用项目类型因素,并将区域驱动因素应用于发票总额。 Sin-tax 将链接到 ItemTypeLocale dyad,并应用于行项目级别。

      【讨论】:

        【解决方案5】:

        1/ 我觉得你也需要考虑顺序

        例如价格 - 折扣 + 销售税显然是可以接受的,但价格 + 销售税 - 折扣不是价格 - (折扣 + 销售税)

        2/ 我会考虑将价格放在另一张桌子上。这不是所售商品的详细信息吗?例如。小部件,蓝色,20.00 美元。而您的因素是销售类型的详细信息。据推测,您可能有一组因素用于步入式零售,另一组用于在线销售,第三组用于批发销售。您可以根据基本价格 * 因素计算这三种销售类型的实际价格。

        3/ 我认为你需要更多的桌子;例如可能是项目、销售类型以及 factor_details 和 factor_rules。您的奢侈品示例可能涵盖了您的销售类型,在这种情况下(如果一个项目只有一种销售类型),这可能在项目表中。 Factor_rules 将详细说明计算公式和 factor_details 值。

        我觉得这很有趣。如果您解决了这个问题,我会很感激您用您的经验更新这个问题。

        【讨论】:

        • 序列已经被考虑和包括在内。为了简单起见,我没有将它包含在这个讨论中(基本上,记录条目的顺序暗示​​了顺序)。我仍在分析问题并考虑您的建议。谢谢。
        • 在关系数据中,您不能依赖序列作为位置因素。也就是说,您将数据按给定顺序放入表中,但这并不意味着它按该顺序返回。有一天,优化器可能会选择另一条访问路径并以不同的顺序返回数据,这可能会破坏您的隐含顺序
        • 正确。这就是为什么我在实际模型中确实有一个序列指示器。为了简单起见,我在这里省略了它。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-04-02
        • 2022-01-25
        • 2015-09-09
        • 1970-01-01
        • 1970-01-01
        • 2016-07-11
        • 2017-08-02
        相关资源
        最近更新 更多