在进入模式和表之前,我想分享一下我首先要实现的目标。我正在开发一种快递应用程序,其中有一些categories
,每个类别都有一个预定义的price
。
但是,确定价格有点丑陋(没有对称性和图案;至少,我似乎找不到任何东西)。我给你举个例子:
请考虑以下类别:文档,重型文档,笔记本电脑,纸箱,重型纸箱。
1)文档:适用于重量小于0.5kg的较浅的文档。价格是20美元,固定的。
[价格表中存储的价格:20.00]
例如一件300克的价格为20美元。
2)较重的文件:这适用于重量超过0.5kg的文件。与“文档”类别不同,它没有固定价格!相反,它有一个单位价格:每公斤10美元,除0.5公斤/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
。这有点类似于文档类别。对于低于3立方英尺(CF)的纸箱,价格为每CF 80美元。单据和纸箱类别之间的区别在于,单据具有固定价格,而纸箱具有单价。但是,等等,还有更多。还有一个额外的约束:尺寸重量比。在这种情况下,它是7kg per CF
。如果商品的重量超过比例,则每增加1公斤,就要收取5美元。我知道这太令人困惑了。一个示例可能会有所帮助:
[价格表中存储的价格:80.00]
例如纸箱80公斤和2CF;价格将为490 $。方法如下:
首先计算常规费用:80 $ * 2CF = 160 $ 现在,让我们找出它是否穿过 Ratio :由于1 CF = 7kg,因此2CF = 14kg。但是该商品的重量为80kg,因此它超过了比例(14kg)
由于它超出了比率,因此,对于所有额外的千克(80-14 = 66千克),每千克将花费5美元:66 * 5 = 330美元。加上常规费用后:330 $ + 160 $ = 490 $。
5)重型纸箱:该纸箱用于尺寸大于3CF的纸箱。与纸箱的区别是单价。重型纸箱每CF为60美元。
[价格表中存储的价格:60.00]
例如纸箱80公斤和5CF;价格将为525 $。方法如下:
首先计算常规费用:60 $ * 5CF = 300 $ 现在,让我们找出它是否穿过 Ratio :由于1 CF = 7kg,因此5CF = 35kg。但是该商品的重量为80kg,所以它超过了35kg的比例
由于它超出了比率,因此,对于所有额外的千克(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
表的架构(这是一个多态表,希望有朝一日创建一个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 | |
+----------------+---------------------+------+-----+---------+----------------+
我如何改善这种结构以保持事物的动态性和连贯性?
答案 0 :(得分: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美元以上包裹的保险,固定时间或类似地点的送达服务。
您提到了子类别和“多态价格表”,但尚不清楚要使用它做什么。如果您有一些无法在像这样的矩阵表中表述的具体示例,请添加它们。但是,您还应该意识到,无论是对于您还是对客户而言,简单性都是至上的。如果您认为我的240$
纸箱收了我的钱10kg/2.99cf
,如果您实际上是向我收取200$
的钱,那么您可能已经迷失了我。装一个重纸箱。