Asa*_*din 5 sql-server database-design referential-integrity foreign-key-relationship sql-server-2008
可能重复:
外键约束可能导致循环或多个级联路径?
我有一个联系人详细信息数据库,其中包含四个主要表:
这是一个图表(箭头表示外键约束):
重要提示:我不小心将绿色箭头标记为指向per_PerID.它应该指向per_SecID

我创建了约束,确保每个部门记录属于一个组织,每个部分属于一个部门,等等.这些外键约束的操作设置为CASCADE,因此删除组织将删除所有相应的部门等.
问题是每个组织都需要有一个负责人.这将转换为字段上的外键约束,该约束将包含负责人的ID.创建约束很简单,但是当我尝试将操作设置ON DELETE为时SET NULL,我收到以下错误:
在表格上引入FOREIGN KEY约束...可能会导致循环或多个级联路径.指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束.
我的理由是,只有当我设置动作时才会发生循环,但CASCADE不是SET NULL,但显然这是不正确的.
- 人员记录已删除
org_incharge_PerID在相应的组织记录中设置为null- 没有进一步的传播.如果组织已被删除,则会出现问题,因为部门也会引用组织.事实上,不应该有问题.
是否有另一种方法可以确保引用完整性,还是应该重新考虑我的表结构,以一种可以完全避免周期问题的方式?
我想要的是org_incharge_PerID被限制per_PerID在人员表中的s 集合.此外,NULL如果删除该人,我希望将值设置为.
一旦遇到循环警告,在不更改数据库结构的情况下确保参照完整性的唯一方法是使用其中一个约束的触发器.触发警告的问题有两个:
Sections表与表共享两个相反方向的外键约束Persons.此外,桌面设计存在一个问题:它的构造方式,一个人可能负责一个他不是其成员的部分.
您可以通过删除得到大约两个三个问题,InCharge从列Sections,并引入另一个表,SectionInCharge包含列PerID和SecID,与上一个聚集索引/唯一约束SecID和复合外键Persons表上的两列.您需要为表中的两列添加UNIQUE约束,Persons以便FK可以与它们相关联.
现在,您可以将新FK设置为ON DELETE CASCADE并删除.
使用行的存在或不存在来表示某些东西而不是使用可空列,这通常是一种优越的数据库设计模式.
现在我考虑一下,带有"负责人"栏目的其他表格在允许分配不正确成员的人方面存在类似的问题.我知道用FK解决这个问题的唯一方法(在我看来是触发器的最佳实践)是通过表传播列并将它们包含在复合键中.这有一个令人遗憾的副作用,使事情变得有点尴尬,但它并不是太糟糕,因为你可以把最具体的列放在第一位,并尽可能只加入它.所以,你会放ORGID在Section表中,与复合FK对DEPT表(DeptID, OrgID),然后把DeptID和OrgID也在Persons表.然后你需要DeptInCharge和OrgInCharge表格.
您可能感兴趣的另一个关于此问题的说明(这不是解决您提出的核心问题)可能是将您的三个底部表格合并到一个表格中OrgUnit.添加OrgUnitType列和ParentOrgID列.当事物不具有该属性时(如在没有传真号的章节中)添加将为NULL的列,或者创建OrgUnit的现有组织,部门和章节表子类型(DB超类型/子类型的示例).这样做的好处是,您可以在任何地方引用三种类型中的任何一种:如果FK是OrgUnit,它可以是其中任何一种.但是如果只允许它成为一个部分,那么你将FK改为该表.事实上,这对于单个OrgUnitInCharge表来说是完美的,FK为OrgUnit (OrgUnitID, OrgUnitTypeID).
我知道这里有一些松散的结局,我没有把它完全捆绑到一个漂亮的包中,但我希望到目前为止我所描述的内容是有帮助的.
PS我希望你能原谅我加入风格的考虑.对我来说,在每个表的每一列上放置一个表格符号前缀是一个额外的不必要的装饰.我根据我的感觉输入90-110每分钟,但我仍然讨厌打字比我更多.此外,我非常坚信在我的代码中保持高信噪比,对我而言,遍布整个地方的前缀大大减少了这一点.在SQL查询中,最佳做法是使用表别名,然后在每列上使用这些别名,如SELECT P.Name FROM dbo.Person P.为了解决具有相同列名的多个表的问题,我已经开始WidgetName在我的Widget表中使用典型列Widget.作为高信噪比为何如此重要的一个例子:vrbauxCan proYou verRead artThis nouSentence advQuickly conAndily?诚然,附加前缀包含有用的信息,但有用的信息是只有一点有用的,和很多分心.如果你现在正在从零开始设计你的数据库,我想请求,因为有些人可能会因为某种奇怪的巧合而最终维持它(发生了奇怪的事情),你不使用这些前缀.:)
PPS我喜欢PascalCase而不是under_scores,因为它更容易输入.下划线位于顶行并被最弱的手指击中 - 因此它更慢且容易出错.
PPPS我也更喜欢单数表名,但这既不是在这里也不是它?我提前道歉,用风格批评打你.