【问题标题】:How to improve this patternless database schema?如何改进这种无模式数据库模式?
【发布时间】:2019-01-18 18:36:30
【问题描述】:

在进入架构和表之前,我想先分享一下我想要实现的目标。我正在开发一种快递应用程序,其中有一些categories,每个类别都有一个预定义的price

但是,确定价格有点难看(缺乏对称性和图案;至少,我似乎找不到任何东西)。我举个例子:

考虑以下类别:文档、重型文档、笔记本电脑、纸箱、重型纸箱。

1) 文件: 适用于重量较轻的文件,重量在 0.5 公斤以下。价格是 20 美元,固定的。

[价格表中存储的价格:20.00]

例如一件 300 克的商品,价格为 20 美元。

2) 重型文件: 适用于超过 0.5 公斤的文件。与文档类别不同,它没有固定价格!相反,它有一个单价:每公斤 10 美元,这将适用于每公斤 0.5 公斤以外/之后的价格。

[价格表中存储的价格:10.00]

例如一件 2 公斤的商品,价格为 35 美元(1.5 克 = 15 美元 + 0.5 = 20 美元)

3) 笔记本电脑:简单明了,100 美元。没什么特别的,没有任何约束。

[价格表中存储的价格:100.00]

例如一件 2 公斤的商品,价格为 35 美元(1.5 克 = 15 美元 + 0.5 = 20 美元)

4) 纸箱:来了一个有趣的。到目前为止,只有一个依赖项:weight。但是这个有一个额外的依赖:dimension。这有点类似于 Document 类别。对于 3 立方英尺 (CF) 以下的纸箱,价格为每 CF 80 美元。 Document 和 Carton 类别之间的区别在于,Document 具有固定价格,而 Carton 具有单价。但是等等,还有更多。还有一个额外的限制:尺寸重量比。在这种情况下,它是7kg per CF。如果物品的重量超过该比例,每增加一公斤,将收取 5 美元。这太令人困惑了,我知道。一个例子可能会有所帮助:

[价格表中存储的价格:80.00]

例如适用于 80kg 和 2CF 的纸箱;价格为 490 美元。方法如下:

先计算常规费用:80$*2CF = 160$ 现在让我们计算它是否超过比率:因为,1 CF = 7kg,因此,2CF = 14kg。但是物品的重量是 80 公斤,所以它超过了比例(14 公斤)

由于超过了这个比例,对于所有额外的公斤(80-14 = 66 公斤),每公斤将花费 5 美元:66 * 5 = 330 美元。加上正常费用后:330$+160$ = 490$。

5) Heavy Carton:这个适用于尺寸大于3CF的纸箱。与纸箱的区别在于单价。重型纸箱每 CF 60 美元。

[价格表中存储的价格:60.00]

例如适用于 80kg 和 5CF 的纸箱;价格为 525 美元。方法如下:

先计算常规费用:60$*5CF = 300$ 现在让我们计算它是否超过 Ratio:因为,1 CF = 7kg,因此,5CF = 35kg。但是物品的重量是 80 公斤,所以它超过了比例(35 公斤)

由于超过了这个比例,对于所有额外的公斤(80-35 = 45 公斤),每公斤将花费 5 美元:45*5 = 225 美元。加上正常费用后:300$+225$ = 325$。

如果您读到这里,我想我已经让您相信业务结构确实很复杂。现在让我们看看我的categories 架构:

+-------------------------+---------------------------------+------+-----+---------+----------------+
| Field                   | Type                            | Null | Key | Default | Extra          |
+-------------------------+---------------------------------+------+-----+---------+----------------+
| id                      | int(10) unsigned                | NO   | PRI | NULL    | auto_increment |
| name                    | varchar(191)                    | NO   |     | NULL    |                |
| created_at              | timestamp                       | YES  |     | NULL    |                |
| updated_at              | timestamp                       | YES  |     | NULL    |                |
| dim_dependency          | tinyint(1)                      | NO   |     | NULL    |                |
| weight_dependency       | tinyint(1)                      | NO   |     | NULL    |                |
| distance_dependency     | tinyint(1)                      | NO   |     | NULL    |                |
| dim_weight_ratio        | varchar(191)                    | YES  |     | NULL    |                |
| constraint_value        | decimal(8,2)                    | YES  |     | NULL    |                |
| constraint_on           | enum('weight','dim')            | YES  |     | NULL    |                |
| size                    | enum('short','regular','large') | YES  |     | regular |                |
| over_ratio_price_per_kg | decimal(8,2)                    | YES  |     | NULL    |                |
| deleted_at              | timestamp                       | YES  |     | NULL    |                |
+-------------------------+---------------------------------+------+-----+---------+----------------+

还有prices表的schema(是多态表,希望有朝一日能创建subcategories表):

+----------------+---------------------+------+-----+---------+----------------+
| Field          | Type                | Null | Key | Default | Extra          |
+----------------+---------------------+------+-----+---------+----------------+
| id             | int(10) unsigned    | NO   | PRI | NULL    | auto_increment |
| amount         | decimal(8,2)        | NO   |     | NULL    |                |
| created_at     | timestamp           | YES  |     | NULL    |                |
| updated_at     | timestamp           | YES  |     | NULL    |                |
| priceable_type | varchar(191)        | NO   | MUL | NULL    |                |
| priceable_id   | bigint(20) unsigned | NO   |     | NULL    |                |
| deleted_at     | timestamp           | YES  |     | NULL    |                |
+----------------+---------------------+------+-----+---------+----------------+

我如何改进这种结构以尽可能保持动态和连贯性?

【问题讨论】:

  • 这里有不同的意见。问题是:是否可以使用 SQL DB 代替规则引擎? 有时可以,但它是最优的还是可取的?考虑使用规则引擎 - 或服务(纯代码) - 用于规则并使用 DB 仅用于记录谓词 User (USR) got price (PRI) for product (PRD) based on rule number (RNO). 您可以在不同的系统中记录规则。

标签: mysql database-design relational-database


【解决方案1】:

因此,如果我想发送 10kg/2.99cf 包裹,您向我收取 240$ (3*80$) 的纸箱费用。如果我把那个包裹放在一个稍微大一点的盒子里,现在想把它作为10kg/3.01cf 包裹寄出,你向我收取180$(3*60$) 的重型纸箱费用。如果你四舍五入到下一个完整的cf,假设我想发送一个80kg/3CF 包;你向我收费535$ (3*80+59*5)。如果我把同一个包裹放在一个更大的盒子里,上面有80kg/4CF,你只收500$ (4*60+52*5)。

这确实是一个好兆头“业务结构真的很复杂”(即使这些可能只是示例值,它也显示出使事情过于复杂的可能性)。

无论如何,我可能会将您的条件编码在这样的表格中:

category |max_kg|max_cf|is_laptop|price|p_p_kg|p_p_cf|off_kg|off_cf|off_rat
---------+------+------+---------+-----+------+------+------+------+--------
Document | 0.5  | null |    0    |  20 |   0  |   0  |  0   |  0   |  0     
Heavy Doc|  2   | null |    0    |  20 |  10  |   0  | 0.5  |  0   |  0   
Laptop   | null | null |    1    | 100 |   0  |   0  |  0   |  0   |  0  
Carton   | null |   3  |    0    |   0 |   5  |  80  |  0   |  0   |  7  
Heavy C. | null | null |    0    | 180 |   5  |  60  |  0   |  3   |  7  

文档也可能有一些大小限制(例如,我可以将我的0.0kg/100cf氦气填充气球作为文档发送吗?),但您没有指定它们;以这种方式列出条件应该可以让您在不特定条件的情况下变得明显。

off_* 指定偏移量,例如price中已经包含的金额; p_p_kg 是剩余重量的每公斤价格(通过偏移量减少),类似于p_p_cf。因此,带有80kg/4CF 的重型纸箱将计算为

price    -- 180
+ p_p_kg * greatest(kg - off_rat * cf - off_kg, 0)  -- 5 * (80-7*4-0) 
+ p_p_cf * greatest(cf - off_cf, 0) -- 60 * (4 - 3)

所以,正如预期的那样,180 + 5 * 52 + 60 = 500

用户不会来到您的商店并说“我想将它作为重型纸箱发送”。他会说:“我寄件重 80 公斤、有 3 cf 且不是笔记本电脑的东西要花多少钱。” 他可能会希望你不要把它作为一个纸箱寄出,如果是一个重型的纸箱会更便宜。

因此,您使用此输入(以及任何其他相关输入,例如距离)并检查所有满足条件的行,例如

select (your price formula depending on input) as cost
...
where (max_kg is null or max_kg >= 80) 
  and (max_cf is null or max_cf >= 3)
  and (is_laptop is null or is_laptop = 0)
order by cost

您可能应该在一个地方定义它,这样更容易添加额外的条件(例如区别)和表中未定义的其他规范(例如四舍五入到完整的cf 或 0.1 的步长)。

您可能还需要一张提供额外服务的桌子,例如快递或隔夜送货、超过 500 美元的包裹保险、固定时间送货或类似服务。

您提到了子类别和“多态价格表”,但不清楚您想用它做什么。如果您有一些无法在这样的矩阵表中表述的具体示例,请添加它们。但您也应该意识到,简单是王道,对您和客户来说都是如此。如果我认为你对我的10kg/2.99cf 纸箱收取240$ 的费用,如果你的竞争对手收取200$ 的费用,你可能已经失去了我,即使你实际上只是向我收取180$ 的重型纸箱费用。

【讨论】:

  • ...不过话说回来,这家店的快递服务可能会比普通服务便宜
猜你喜欢
  • 2017-08-27
  • 1970-01-01
  • 1970-01-01
  • 2013-06-07
  • 2011-10-16
  • 2015-05-02
  • 1970-01-01
  • 1970-01-01
  • 2020-01-05
相关资源
最近更新 更多