Database 如何表示当前状态或状态并维护数据/引用完整性?-数据库设计
我有一个表,用于维护特定的业务事务,我们称之为Database 如何表示当前状态或状态并维护数据/引用完整性?-数据库设计,database,database-design,relational-database,Database,Database Design,Relational Database,我有一个表,用于维护特定的业务事务,我们称之为LOANS。每个记录在任何给定时间都可以有几个“状态”中的一个,例如“重新付款/打开”、“默认”、“作废”或“已付款” 记录的状态只能因“事件”或应用程序用户采取的操作而更改(某些事件不会导致状态更改,例如付款会修改记录,但不会更改状态)。在跟踪当前状态的同时,我们可以轻松地跟踪使事务处于这种状态的“事件”,这一点也很重要 我见过其他数据库的设置,例如LOANS包含一个status列,并使用一个字母(甚至是可能状态表的外键)来指定当前状态。然后,事件
LOANS
。每个记录在任何给定时间都可以有几个“状态”中的一个,例如“重新付款/打开”、“默认”、“作废”或“已付款”
记录的状态只能因“事件”或应用程序用户采取的操作而更改(某些事件不会导致状态更改,例如付款会修改记录,但不会更改状态)。在跟踪当前状态的同时,我们可以轻松地跟踪使事务处于这种状态的“事件”,这一点也很重要
我见过其他数据库的设置,例如LOANS
包含一个status列,并使用一个字母(甚至是可能状态表的外键)来指定当前状态。然后,事件
表中有一列是FK
到贷款
此解决方案可行,但我担心这可能会导致数据完整性丢失。换句话说,没有任何东西可以阻止将状态设置为“defaulted”(默认),并且没有事件来支持更改。这将完全由应用程序来确保不会发生这种情况(在我看来,这个解决方案中没有引用完整性)
我的替代解决方案是取消LOANS
中的status列,而是使用lastEvent
列,该列是事件的FK。EVENTS
表将维护事件的“类型”,该类型将依次描述状态变化(例如,如果lastEvent
为“payoff”类型,则状态自然为“payed”)
我的问题是:
我是否应该关心数据的完整性(这是一件很常见的事情,因为这样做是可以的)
我提出的解决方案是合理的,还是有更好的解决方案
我的解决方案中是否有任何陷阱需要注意
如果有必要,我使用的是MS SQL SERVER 2005。我认为您对完整性的关注是正确的。您指定了一个业务规则,该规则声明,实际上状态不是一个可写属性,它是从事件推断出来的
我会根据你的事件数据做一个调查
我们只能猜测您的db实现,所以另一种选择是触发器更新列,但如何确保它是只读的?(可能带有锁/权限)
只有您知道如果您在这里没有引用完整性会有什么风险,但是一般来说,是的,设计数据库以便使用引用完整性是值得的。它减少了错误,增加了未来开发人员理解您的模式的机会
我会有一个大致如下的模式
贷款
贷款Id(PK)
数量
事件
事件id(主键)
贷款ID(FK)
事件类型标识(FK)
日期
身份证(fk)
事件类型
事件类型id(主键)
描述
地位
状态标识(pk)
描述
要查找任何负载的当前状态,您需要在事件表中查找该贷款的最新条目。要查看贷款状态更改的历史记录,可以查询事件表
当您记录不改变状态的事件时,带有新事件的记录只包含事件的当前状态-因此您可能会得到如下表:
Event_id Loan_ID Event_type_id Date status_id
------------------------------------------------
1 1 NEW 1 Jan 2011 NEW
2 1 APPROVE 2 Jan 2011 NEW
3 1 DEFAULT 1 Feb 2011 DEF
...
这样,您总是通过查找最新记录来检索当前状态
它极大地降低了错误的风险——如果“事件”的逻辑发生了变化,并且某个事件确实改变了贷款的状态,那么您只需在一个地方进行更改——即在事件数据库中创建记录的代码。您不必记住也要更改“贷款”记录
至于性能——我只会在您真正需要的时候对此进行优化——在经过良好调优的数据库上,join和max不应该是show stopper
您可以通过创建映射有效状态转换及其关联事件的表来优化模型;根据您的数据库,您可以通过触发器强制执行此操作
我认为这比“last event”外键更好,因为它是多余的-根据定义,last event是该贷款的最大(日期)记录。我使用的是SQL SERVER 2005,为了清晰起见,在问题中添加了它。计算列在2005年可用,请参阅链接顶部的“其他版本”,因为某些事件不会更改状态,这也是我选择不看最后一个事件的原因之一(但也许我可以推断,不改变状态的事件需要一个初始状态来开始)。另一个原因是我认为在lastEvent中存储它可能比每次我想要某个特定状态的所有项目时调用MAX(date)要快(这种类型的调用会经常发生)。