http://weblogs.sqlteam.com/jeffs/archive/2008/08/13.aspx:
考虑以下逻辑数据模型:
*有多家公司 *每个公司都有很多项目 *每个项目都有很多任务 *每个任务都有一个状态,从全局预定义状态列表中选择。我们假设我们认为公司,项目,任务和状态的主键都是标识(自动编号)列,因为我们希望为这些表自动生成主键。
基本上,我们有4个表:
状态(PK:StatusID)
公司(PK:CompanyID)
项目(PK:ProjectID,FK:[Companies] .CompanyID)
任务(PK:TaskID,FK:[Projects] .ProjectID,[Status] .StatusID)。
现在,请允许我添加一点皱纹。假设每个任务的可用状态未在全局定义,而是在公司级别定义。也就是说,每个公司都有自己的状态列表,可以为其分配任务。
这意味着Status表现在需要对Companies表的外键引用(以指示每个Status所属的公司):
公司(PK:CompanyID)
状态(PK:StatusID,FK:[公司]。公司ID)
项目(PK:ProjectID,FK:[Companies] .CompanyID)
任务(PK:TaskID,FK:[Projects] .ProjectID,[Status] .StatusID)。
我们需要对此数据模型进行任何其他更改吗?或者只是简单地将一个CompanyID列添加到Status表中以促进此更改?请记住,我们的目标始终是尽可能使用主键和外键约束的完全引用完整性。
嗯,有一个问题:
此数据模型中没有任何内容阻止我们将状态分配给未为该任务的母公司定义的任务。我们目前的限制条件无法立即执行此操作。我们的物理数据模型存在缺陷。
这很容易解决,但只能通过违反“所有表只需要一个身份主键”规则来完成。
首先,请记住这一点:仅仅因为标识列是唯一的并不意味着该列不能是主键的部分。
他继续指出如何使用复合键来完全强制和约束您的数据模型:
公司(PK:CompanyID)
状态(PK:CompanyID,StatusID,FK:[Companies] .CompanyID)
项目(PK:CompanyID,ProjectID,FK:[Companies] .CompanyID)
任务(PK:TaskID,FK:[Projects]。(CompanyID,ProjectID),[Status]。(CompanyID,StatusID))。
我长期以来一直是完全执行/约束我的数据模型的粉丝,但是,我经常发现自己处于类似于前面提到的情况,我来到了一个十字路口:
完全执行或不完全执行。
显而易见的缺点是看似过于复杂的设计。
现在,我知道不一定是“正确”的设计,但对于这样的情况......我正在寻找最佳实践方面的反馈。
有关此设计的优点,缺点和一般想法,还是完全执行您的数据模型设计?
**请注意,这个问题可能引发关于在执行数据模型(数据库或应用程序或两者)方面的责任所在的争论。为了便于讨论,我相信您的数据模型应该强制执行 - 请在此假设下回答。 **
答案 0 :(得分:2)
我会在CompanyStatus
和Company
之间创建一个多对多的Status
表,并说明哪种状态适用于给定的公司。然后,为任务分配CompanyStatusID
而不是StatusID
。
这也可以防止您在Status
表中出现重复状态 - 例如,许多公司可以共享相同的已关闭状态,这样可以更好地进行规范化。
因此,您不需要使用复合键来正确实施约束。我更喜欢使用没有意义的单个自动增量主键(代理键)。这比假设一个密钥是唯一的(例如SSN)更有效,当总是有可能结果不是这样的情况时,你必须存储数据,因为应用程序需要它(所以一个独特的约束在这里没有帮助。)