171 sql sql-server constraints
当我尝试向表格添加约束时,我遇到了问题.我收到错误:
在表'Employee'上引入FOREIGN KEY约束'FK74988DB24B3C886'可能会导致循环或多个级联路径.指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束.
我的约束是在Code
表和employee
表之间.该Code
表包括Id
,Name
,FriendlyName
,Type
和Value
.在employee
具有许多参考代码,使得可以存在对于每种类型的码的参考字段.
如果删除引用的代码,我需要将字段设置为null.
我有什么想法可以做到这一点?
one*_*hen 173
SQL Server对级联路径进行简单计数,而不是试图确定是否存在任何周期,它假设最坏的并拒绝创建引用操作(CASCADE):您可以而且应该仍然创建没有引用操作的约束.如果你不能改变你的设计(或者这样做会损害你的设计)那么你应该考虑使用触发器作为最后的手段.
FWIW解析级联路径是一个复杂的问题.其他SQL产品将简单地忽略该问题并允许您创建循环,在这种情况下,它将是一个竞争,看看哪个将覆盖最后的值,可能是对设计者的无知(例如ACE/Jet这样做).我理解一些SQL产品将尝试解决简单的情况.事实仍然是,SQL Server甚至没有尝试,通过禁止多条路径来播放它是非常安全的,至少它会告诉你.
微软自己建议使用触发器而不是FK约束.
小智 89
具有多个级联路径的典型情况是:具有两个细节的主表,例如"Master"和"Detail1"和"Detail2".这两个细节都是级联删除.到目前为止没有问题.但是,如果两个细节与其他一些表(例如"SomeOtherTable")具有一对多的关系,那该怎么办呢?SomeOtherTable具有Detail1ID列和Detail2ID列.
Master { ID, masterfields }
Detail1 { ID, MasterID, detail1fields }
Detail2 { ID, MasterID, detail2fields }
SomeOtherTable {ID, Detail1ID, Detail2ID, someothertablefields }
Run Code Online (Sandbox Code Playgroud)
换句话说:SomeOtherTable中的一些记录与Detail1-records链接,SomeOtherTable中的一些记录与Detail2记录链接.即使保证SomeOtherTable记录永远不属于两个细节,现在也不可能为这两个细节制作SomeOhterTable的记录级联删除,因为从Master到SomeOtherTable有多个级联路径(一个通过Detail1,一个通过Detail2).现在你可能已经理解了这一点.这是一个可能的解决方案:
Master { ID, masterfields }
DetailMain { ID, MasterID }
Detail1 { DetailMainID, detail1fields }
Detail2 { DetailMainID, detail2fields }
SomeOtherTable {ID, DetailMainID, someothertablefields }
Run Code Online (Sandbox Code Playgroud)
所有ID字段都是关键字段和自动递增.关键在于Detail表的DetailMainId字段.这些字段既是关键的,也是参考的约束.现在可以通过仅删除主记录来级联删除所有内容.缺点是对于每个detail1-record和每个detail2记录,还必须有一个DetailMain记录(实际上是先创建它以获得正确且唯一的id).
Bil*_*gan 12
我会指出(功能上)在SCHEMA和DATA中循环和/或多个路径之间存在巨大差异.虽然DATA中的循环和可能的多路径肯定会使处理变得复杂并导致性能问题("正确"处理的成本),但架构中这些特性的成本应该接近于零.
由于RDB中的大多数明显周期都出现在层次结构(组织结构图,部分,子部分等)中,因此不幸的是SQL Server假设最糟糕; 即,架构周期==数据周期.实际上,如果您使用RI约束,则无法在数据中实际构建循环!
我怀疑多路径问题是类似的; 即,模式中的多个路径不一定意味着数据中的多个路径,但我对多路径问题的经验较少.
当然,如果SQL Server 确实允许循环,它仍然会受到32的深度限制,但这对大多数情况来说可能已经足够了.(太糟糕了,但这不是数据库设置!)
"而不是删除"触发器也不起作用.第二次访问表时,将忽略触发器.因此,如果您真的想要模拟级联,则必须在存在循环的情况下使用存储过程.但是,替代删除触发器适用于多路径情况.
Celko提出了一种"更好"的方式来表示不引入周期的层次结构,但存在权衡.
有一篇文章介绍了如何使用触发器执行多个删除路径.也许这对复杂场景很有用.