循环或多个级联路径删除时设置为空:真的吗?

Ger*_*old 10 sql-server cascade

我问这个问题是为了检查我关于级联删除的推理是否正确,以及我是否没有忽略任何东西。我理解这种行为,我不是在问为什么在当前的限制下实施它。

当我们尝试创建一个包含像这样的自引用的表时:

CREATE TABLE [BlogComments] (
    [Id] int NOT NULL IDENTITY,
    [AuthorName] nvarchar(100) NULL,
    [Content] nvarchar(max) NULL,
    [CreatedTime] datetime2 NOT NULL,
    [ReplyToId] int NULL,
    CONSTRAINT [PK_BlogComments] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_BlogComments_BlogComments_ReplyToId] FOREIGN KEY ([ReplyToId])
         REFERENCES [BlogComments] ([Id]) ON DELETE SET NULL -- Not: CASCADE
);
Run Code Online (Sandbox Code Playgroud)

我们得到了臭名昭著的异常

在表 'BlogComments' 上引入 FOREIGN KEY 约束 'FK_BlogComments_BlogComments_ReplyToId' 可能会导致循环或多个级联路径。

我知道该设置ON DELETE SET CASCADE实际上可能会导致删除的递归级联,因此可能很危险,或者充其量是耗时的。但ON DELETE SET NULL不同的是:它只会使ReplyToId直接子记录无效,而不会使它们的子记录无效。

那么我得出的结论是,当外键定义为 SQL Server 时,SQL Server 的限制性太强了ON DELETE SET NULL吗?或者我是否忽略了在这种特殊情况下进行此限制的一些充分理由?

顺便说一下,我知道有一种观点认为无论如何都不应该有任何级联操作。让我们不要进入那个。

Mik*_*son 5

创建可能导致多个级联路径的 FOREIGN KEY 约束时出现错误消息 1785

您收到此错误消息的原因是,在 SQL Server 中,一个表不能在由 DELETE 或 UPDATE 语句启动的所有级联引用操作的列表中出现多次。例如,级联引用操作树必须仅具有到级联引用操作树上的特定表的一条路径。

如果 SQL Server 允许自引用,则on delete set null查询计划需要有两个不同的运算符来更改同一个表。第一个删除行,将删除的行存储在假脱机中,并使用该假脱机查找需要更新的行。如果您有一行ReplyIdId相同,它将尝试更新已删除的行的值。或者至少在事务提交后会如此。

我并不是说不可能实现这一点,只是说它比人们第一眼想象的要复杂得多。考虑一下如何处理万圣节保护并向组合中添加触发器和索引视图,然后很快就会进入一些不简单的事情来构建在事务上正确完成工作的计划。

  • @GertArnold 他们(SQL Server 开发人员)对双重更新行有点敏感。至少他们处于“现代”。MERGE 有一个运行时错误来处理这个问题。“MERGE 语句尝试多次更新或删除同一行。当目标行与多个源行匹配时,就会发生这种情况。MERGE 语句无法多次更新/删除目标表的同一行。优化 ON 子句以确保目标行最多匹配一个源行,或使用 GROUP BY 子句对源行进行分组。” (3认同)