租车系统模块与数据库设计.docx
《租车系统模块与数据库设计.docx》由会员分享,可在线阅读,更多相关《租车系统模块与数据库设计.docx(16页珍藏版)》请在冰豆网上搜索。
租车系统模块与数据库设计
最近在看《Databasemodeling&design:
logicaldesign》一书,其中有一道练习题是对简单租车系统进行数据库逻辑设计并画出ER图。
这道题给我挺多遐想的,所以我在这里把这些想法记录下来,也试着设计一把。
要进行数据库设计,首先要对需求进行分析。
需求分析一般会需要对业务人员进行随访,收集信息。
我没办法进行随访,就通过自己的遐想来假设需求场景(可能会有错误与遗漏)。
最初想到的:
1.租车公司有多个租车门店,分布于多个不同的地区,并有各自的租车电话。
2.每个租车门店有多辆汽车可供租赁。
3.供租赁的车辆需要登记车辆识别代号(VIN),购入时间,所属门店,车辆型号,车辆状态(可租Ready,维修中Repair,租出Inuse,无效Inactive)
4.车辆的租用费用基本由车辆型号和日期类型(平日,周末,还是节假日)来决定。
5.顾客在订车前需先进行注册,包括姓名,身份证号,驾照号,性别,手机号,固定电话,家庭住址,Email。
6.注册顾客可通过系统下租车单,预约某车型,若干天的租赁(预约期最远为6个月)。
7.租车单需记录顾客编号,车辆编号,租赁起始日期,租赁结束日期,提车门店,还车门店,租赁费用,预付款金额,订单状态(输入Entered,提交Booked,预约Reserved,使用中Inuse,交还Returned,取消Cancelled)。
注:
暂不提供送车上门和上门取车服务。
对于上述需求,比较明显的需创建的表有:
车辆(Table_Car),门店(Table_Store),顾客(Table_Customer),订单(Table_Order)。
除此之外,车辆型号,车辆状态,日期类型和订单状态分别创建成四张枚举表Table_CarCategory,Table_CarStatus,Table_DateType,Table_OrderStatus。
还应有一张租车价位对照表(Table_BasePrice),其中会包含两个外键分别指向Table_CarCategory,Table_DateType。
简单表关系图如下:
大部分字段的含义大家可以从命名中猜测到。
其中需要注意的有两点:
1.这一设计中有4张枚举表(Table_DateType,Table_CarCategory,Table_OrderStatus,Table_CarStatus),在实际的信息系统或业务系统中这样的枚举表可能非常多。
把这些枚举表整合到一张配置表中会带来哪些好处与哪些坏处?
是否还有其他解决方案?
大家可以进行思考。
2.租车价位对照表在图中被设计成Table_BasePrice。
其主键为一联合键,包括CarCategory_ID(表明车型,如:
乐风1.6MT),DateType_ID(表明是平日,周末或节日),BasePrice_StartDate(表明从哪个时间点开始顾客在系统页面看到新的价格),其中CarCategory_ID,DateType_ID同时为外键。
这是一种设计方式。
另有2种可选的设计方式:
待选方案1.把Table_BasePrice中的DateType_ID去除,Table_BasePrice只存某种车型的初始租价。
在Table_DateType中多加一列DateType_AdjustRate,存放一个大于等于1的比率,如:
平日比率为1.0,双休日为1.1。
某一日的基本租价为:
比率×初始租价。
待选方案2.在待选方案1的基础上,直接去除Table_BasePrice表。
把BasePrice_Price放到Table_CarCategory中(可改名为CarCategory_Price)。
其他修改和方案1相同。
这些方案会影响到系统使用的灵活性,易用性和可追溯性。
大家可以对这些方案的优点和缺点进行思考和讨论。
时间差不多了,要去干活了。
到现在为止,这一数据模型还远未达到基本可使用的阶段。
我们将在其后的篇目中进一步讨论,提出新的需求和挑战,并修改、完善这一设计。
前篇回顾
租车信息系统数据库设计
(1)中我们根据租车系统最基本的一些需求,设计出了如下表结构:
有朋友看了这个结构图后问我为什么对于订单没有设计成主从表(即分为OrderHeader,OrderDetail)。
订单的主从表设计在ERP系统中非常常见,在OrderHeader中存放客户信息,在OrderDetail中存放此客户本次订购的多种产品(每种产品若干数量),这种设计也更符合范式。
我当初在进行设计时,首先想到的也是主从表设计,但思考了租车的需求场景,我最后选择了现在的这一设计。
在我的电影院票务管理系统数据库设计
(2)中对于类似问题进行过详细的分析,所以这里不再展开。
但现在的结构也未必是最符合实际需求的,毕竟我是闭门造车,大家可自己思考提出更合理的设计方案。
Order状态问题
在上一篇中我们设计了6种Order状态,分别是:
输入Entered,提交Booked,预约Reserved,使用中Inuse,交还Returned,取消Cancelled。
对于正常Order的结束状态为Returned,但我在和曾经租过车的同事闲聊后,我觉得需要再加一个Closed状态作为Order结束状态。
一般顾客在还车后,租车公司还会收取约600元的预授权,租车公司会检查该车在租用期是否有违章罚款,如若没有,这笔费用将在约两个月后打回顾客卡内。
只有到这个时候这个Order才真正结束了(预授权的600元也需要记录在Table_Order表中,大家可以自行加一些列,本文为简化不列出了)。
进一步的分析与设计
第一篇中的设计不能满足现实需求的重要一点是,系统中没有记录顾客实际取车和还车的时间,这对于计算实际费用是至关重要的。
当前的设计也无法回答门店库存车辆的变化情况。
还有像车辆的维修信息,保险信息也都没有记录在系统中。
我们把这些新的需求进行整理,接在第一篇的需求列表之后:
8.需记录顾客实际取车和还车的时间,用于计算实际的租车费用。
9.需记录门店库存车辆的变化情况,跟踪每一辆车的进出库信息。
10.记录每辆车的维修历史,包括维修的时间,费用,维修公司,维修合同号。
11.记录每辆车的保险历史,包括保险的时间,费用,保险公司,保险合同号。
12.注册顾客会有多个等级,对于不同等级会给予不同的折扣率(如:
黄金用户有95折的优惠)。
对于需求8,我们要在原先的Table_Order中加入新的列,加入Order_ActualStartDate,Order_ActualEndDate来记录实际取车和还车时间,还要加入Order_ActualPrice来记录实际产生的租车费用。
对于需求9,我们可以加入一张Table_StoreTransaction表来记录车辆的进出库流水。
表中的字段需包括:
发生进出库的车辆ID(Car_ID),表示是进库还是出库的标签(StoreTransaction_InOutFlag),进出库的时间(StoreTransaction_Date)。
Table_Car与Table_StoreTransaction为一对多关系。
对于需求10,我们要加入一张Table_RepairHistory表,Table_Car与Table_RepairHistory为一对多关系。
间接的还会引入一张Table_RepairStation表,来记录维修点信息。
Table_RepairStation与Table_RepairHistory之间也为一对多关系。
对于需求11,加入一张Table_InsuranceHistory表,Table_Car与Table_InsuranceHistory为一对多关系。
间接引入Table_InsuranceCompany表,记录保险公司信息。
Table_InsuranceCompany与Table_InsuranceHistory之间为一对多关系。
对于需求12,加入Table_Class表,表中会存放折扣信息(Class_Discount)。
Table_Class与Table_Customer之间为一对多关系。
新的表关系图如下:
上图中用红色框标出了本次增加或改变的表和字段。
其中需要注意的是Table_StoreTransaction表中用黄色框标出的StoreTransaction_ReferenceID字段。
这个字段存放某次出入库对应的Order_ID,这样就能知道StoreTransaction与Order的对应关系了。
但对于车辆买入,或车辆报废,送修造成的出入库,这一字段暂时还没有对应的数据,这将在下一篇中讨论。
下篇预告
到现在为止租车系统的基本需求已经满足了,但还有不少问题值得思考。
1.出入库管理还能丰富,车辆买入,车辆报废,送修,还有不同门店之间的车辆拆借(如门店A向门店B临时借用某辆车),如何更好的记录这些StoreTransaction信息?
2.顾客对于租车费用的支付信息如何记录,顾客可以通过预先充值后消费的方式来支付(这也是区分会员级别的关键),又该如何支持?
3.我们在第一篇中暂时没考虑“送车上门和上门取车”服务,要支持这一功能,我们对数据库结构要做些什么改动?
前篇回顾
在租车信息系统数据库设计
(1)与租车信息系统数据库设计
(2)中我们列出了租车信息系统的12条需求,并相应做了数据库设计,最后得到的表关系图如下:
在租车信息系统数据库设计
(2)的最后提出了3个新问题:
1.出入库管理还能丰富,车辆买入,车辆报废,送修,还有不同门店之间的车辆拆借(如门店A向门店B临时借用某辆车),如何更好的记录这些StoreTransaction信息?
2.顾客对于租车费用的支付信息如何记录,顾客可以通过预先充值后消费的方式来支付(这也是区分会员级别的关键),又该如何支持?
3.我们在第一篇中暂时没考虑“送车上门和上门取车”服务,要支持这一功能,我们对数据库结构要做些什么改动?
就这3个问题,今天我给出自己的解决方案与大家进行讨论。
更细致的出入库管理
对于问题1,可以通过细分StoreTransaction来解决。
在Table_StoreTransaction表中增加StoreTransaction_Type列来存放进出库类型,我把进出库类型分为3种(Purchase,Adjustment,Rental)。
相应还需要加入两张表Table_Purchase(记录买入车辆的信息),Table_Adjustment(记录车辆拆借、送修、报废信息)。
Table_StoreTransaction表中的StoreTransaction_ReferenceID列根据不同的进出库类型指向不同表中的记录。
下表罗列了各种情况的进出库类型和ReferenceID指向的表:
进出库类型
ReferenceID指向的表记录
车辆出租
Rental(In/Out)
Table_Order
车辆买入
Purchase(In)
Table_Purchase
车辆拆借
Adjustment(In/Out)
Table_Adjustment
车辆送修
Adjustment(In/Out)
Table_Adjustment
车辆报废
Adjustment(Out)
Table_Adjustment
我们来看一下需要新建的表的字段。
实际上,除了要新建Table_Purchase,Table_Adjustment之外,还会间接引入Table_AdjustmentType表。
Table_Purchase:
列名
解释
Purchase_ID
Identity字段
Store_ID
入库门店ID
Car_VIN
车辆唯一编号
CarCategory_ID
车辆型号ID
Purchase_Date
购买日期
Purchase_Price
购买价格
Purchase_Currency
货币
Purchase_CreatedBy
购车申请人
Purchase_AuthorisedBy
购车批准人
Purchase_Comment
购车备注
注意:
1.Table_Purchase表中没有Car_ID字段是因为在车辆买入之前,Table_Car中还没有对应记录。
2.为了简化,我们的设计中Table_Purchase只记录成功购买车辆的信息。
如果想对车辆购买进行像Order一样的流程控制,就需要增加些新的字段和表,如购车状态信息(记录Purchase的状态,如新建,审批通过,取消或完成等),大家自己根据需要添加。
Table_Adjustment:
列名
解释
Adjustment_ID
Identity字段
AdjustmentType_ID
调库类型ID,指向Table_AdjustmentType记录
Store_ID
入库/出库门店ID
Car_ID
车辆ID
Adjustment_Date
调库日期
Adjustment_ExpectDate
预期归还时间
Adjustment_CreatedBy
调库申请人
Adjustment_AuthorisedBy
调库批准人
Adjustment_Comment
调库备注
注意:
1.Adjustment_ExpectDate表示预期归还时间,此字段只有在AdjustmentType对应为BorrowIn,LendOut,SendtoRepair中有意义。
当为其他AdjustmentType时,此字段置为NULL。
2.在此设计中,当某车辆从一个门店AdjustOut后,Table_Car中对应的车辆记录的车辆状态变为Inactive。
当某车辆被AdjustIn到一个门店后,Table_Car中会相应插入一条车辆记录(也有可能只需做Update),且该车辆状态为Ready。
3.对于公司各门店之间的拆借,上述方式之外,大家也可以考虑把个门店也看作内部客户,一个门店可以向另一个门店创建Order,走Order流程。
但借入车辆的门店需要有一种机制来把车辆收入门店,大家可以思考,并比较两种方式的优劣。
Table_AdjustmentType:
列名
解释
AdjustmentType_ID
Identity字段
AdjustmentType_Name
调库类型,包括:
借入BorrowIn,借出LendOut,归还ReturnIn,返还ReturnOut,送修SendtoRepair,修完入库ReturnafterRepair,报废Scrap
AdjustmentType_InOutFlag
进出库标签
注意:
本设计中AdjustmentType分得较细,通过AdjustmentType就能区分是入库还是出库。
另一种设计是用较少的AdjustmentType来区分调库的种类(如只有Borrow,Return,Repair,Scrap四种),通过InOutFlag来区分进/出库。
若要这么做就需要把InOutFlag字段放到Table_Adjustment中。
至于两种方式的有缺点,大家可以思考。
新的表关系图
由于加入新的表之后,表关系链接出现了交错。
所以我使用了数据库的‘自动整理表’功能把关系图重新排列了一下,得到下图:
其中用红色框圈出的表是这次新加入的表。
其中用黄色圈出的几个字段是我们需要注意的:
1.在先前的Table_Car中(本文开始的关系图),有字段Car_PurchasePrice,Car_Currency。
我们引入了Table_Purchase表之后,这两个字段的信息有冗余,可以省去。
我把其中的Car_PurchasePrice改为了Car_CurrentPrice,用于记录每年折损后的车辆价值。
2.在租车信息系统数据库设计
(2)中,Table_StoreTransaction表中的StoreTransaction_ReferenceID字段对于车辆买入,车辆拆借、车辆报废和送修造成的出入库没有对应的信息。
现在对于上述情况,此字段将引用Table_Purchase或Table_Adjustment的ID列。
下篇预告
没想到第一个问题就写了这么多,剩下的问题来不及写了,只能留到下一篇中讨论。
2.顾客对于租车费用的支付信息如何记录,顾客可以通过预先充值后消费的方式来支付(这也是区分会员级别的关键),该如何支持?
3.我们在第一篇中暂时没考虑“送车上门和上门取车”服务,要支持这一功能,我们对数据库结构要做些什么改动?
前篇回顾
在租车信息系统数据库设计(3)中我们实现了更为细致的车辆出入库管理。
本篇将试图解决剩下的2个问题:
1.顾客对于租车费用的支付信息如何记录,顾客可以通过预先充值后消费的方式来支付(这也是区分会员级别的关键),该如何支持?
2.我们在第一篇中暂时没考虑“送车上门和上门取车”服务,要支持这一功能,我们对数据库结构要做些什么改动?
1、支付管理
对于租车费用的支付,我想到了如下几个关键点:
1)顾客可以预先向会员卡充值,之后进行消费。
2)对于一个订单的费用,支付来源可以有多个。
例如:
订单总费用2500元,顾客选择先用完会员卡中的1000元,再刷卡1500元进行支付。
3)对于顾客的一次支付,可以对应多个Order。
例如:
顾客租用了2辆车,在我们的系统中会对应2个Order,顾客可以1次刷卡支付这2个Order的全部费用。
对于关键点1,我们要在系统中为每个顾客创建账户(Account),顾客向会员卡充值或使用会员卡消费都对于一笔流水(Transaction)。
对于关键点2、3,说明了订单与顾客支付之间是一种多对多关系。
我的解决方案如下:
1.在原先的Table_Customer表中增加Customer_AccountBalance,Customer_AccountCurrency字段,存放顾客账户结余。
需要注意的是这个字段的信息是可以通过累加该顾客所有的账户流水得到,有些冗余但能提高获取账户余额的性能。
Customer_AccountBalance和账户流水之间是总账和明细账的关系,需要计划一些时间点进行结算(即总账与明细账轧平)。
2.增加Table_AccountTransaction表,即账户流水表,顾客每次充值与支付都会在该表中增加一条记录。
在本设计中,我把顾客支付某Order时的现场刷卡或付现金行为也作为该顾客对自己账户的先充值,之后再从顾客账户扣款支付Order。
这种设计方式能减少表的数量、好理解,但所用的顾客刷卡或付现都进入到了总账,之后再与Order关联,无法很明确的得到顾客的某次刷卡是为了支付哪个特定的Order(你只能通过时间和金额来推测)。
大家对此可以进行思考,给出解决方案,并比较优劣。
Table_AccountTransaction字段
列名
解释
AccountTransaction_ID
Identity字段
Customer_ID
顾客ID,外键
AccountTransactionType_ID
流水类型ID,外键
AccountTransaction_Date
流水产生日期
AccountTransaction_Amount
流水金额(正值为充值,负值为支付)
AccountTransaction_ReferenceID
参考号码
1.充值流水
信用卡:
卡号
支票:
支票号
现金:
为空,
2.支付流水
为空
3.对于Table_AccountTransaction中的AccountTransactionType_ID字段对应新增表Table_AccountTransactionType中的记录。
Table_AccountTransactionType字段
列名
解释
AccountTransactionType_ID
Identity字段
AccountTransactionType_InOutFlag
0为支付,1为充值
AccountTransactionType_Name
账户流水类型名:
1.Cash:
现金充值,对应AccountTransactionType_InOutFlag:
1
2.CreditCard:
信用卡充值,对应AccountTransactionType_InOutFlag:
1
3.Check:
支票充值,对应AccountTransactionType_InOutFlag:
1
4.PayOrder:
支付订单,对应AccountTransactionType_InOutFlag:
0
AccountTransactionType_Description
账户流水类型描述
4.增加Table_PaymentApplication表,这张表建立了Order与AccountTransaction之间的多对多关系。
Table_PaymentApplication字段
列名
解释
PaymentApplication_ID
Identity字段
Order_ID
订单ID,外键
AccountTransaction_ID
账户流水ID,外键
PaymentApplication_Amount
支付金额
PaymentApplication_Date
支付日期
加入支付管理功能后的表关系图
其中用红色标出了新增加的表,用黄色标出了新增加的列。
注意:
1.一般在一个表中有金额字段时,我都会加一个对应的Currency字段来表示货币类型。
在这次新增的Table_AccountTransaction和Table_PaymentApplication中虽有金额字段,但没有对应的Currency字段,这是因为我默认这些记录的Currency与Table_Customer表中新增的Customer_AccountCurrency一致。
大家可以根据需要加上Currency字段。
2.这个支付管理的设计我总感觉不是最好,就如上文解决方案中所说的。
我试图给出了另一种设计(增加Table_Payment表,用以记录用户的支付来源,如信用卡信息等。
简化Table_AccountTransaction表,只保留金额与时间,对于充值记录对应Table_Payment的ID。
对于Table_PaymentApplication,可能有两种来源一种是直接的Payment,对应Table_Payment记录,另一种是用户Account,对应Table_AccountTransaction记录),但也并不满意。
大家可以进行更多的尝试,并欢迎分享。
2、送车上门和上门取车
这个功能是之前省略的,但现在的市场竞争如此激烈。
提供这样的功能来提升用户满意度还是必须的。
对于这个功能有3个要求:
1.系统应允许顾客在创建Order时选择送车上门和上门取车服务,并提供输入界面。
2.顾客首次输入一个新地址后,该地址应被记录系