9

我在一个表中有两个外键。让我们假设 table 被调用News并且有外键updatedByIdand createdById,它们都指向userIdin table Users

现在我想在NULL删除用户时设置为外键,但是当我尝试设置ON DELETE SET NULL该关系时,我得到:

在表“News”上引入 FOREIGN KEY 约束“FK_News_Users”可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。

我不明白为什么两个外键都不能设置为空?

4

3 回答 3

10

多个级联操作

由单个 DELETE 或 UPDATE 触发的一系列级联引用操作必须形成不包含循环引用的树。在由 DELETE 或 UPDATE 产生的所有级联引用操作的列表中,任何表都不能出现多次。此外,级联引用操作的树不能有多个路径到任何指定的表。树的任何分支在遇到未指定 NO ACTION 或为默认值的表时都会结束。

可能在这种情况下,您可能需要考虑实现功能以逻辑方式而不是物理方式删除用户(例如,通过在Users表中引入标志字段 Active 或 Deleted)。这样一来,所有关系都保持不变,并且可以进行回顾性分析。

但是,如果您仍然需要ON DELETE SET NULL为两个 FK 实现,则可以在表上使用FOR DELETE触发器,User如下所示:

CREATE TRIGGER Users_News_Delete_Trigger 
ON Users FOR DELETE
AS BEGIN
    UPDATE News SET createdById = NULL 
     WHERE createdById = DELETED.id;
    UPDATE News SET updatedById = NULL 
     WHERE updatedById = DELETED.id;
END
于 2013-01-28T01:36:14.837 回答
3

一种替代方法是在表 A 和表 B 之间创建一个交叉引用表,其中每个条目是 A.ID 和 B.ID 并且 B.ID 具有 B 的外键。然后您可以简单地对交叉引用进行 CASCADE 删除。您需要在交叉引用中添加第三个字段,以说明引用的唯一目的,例如

[NewsID] INT NOT NULL DEFAULT 0,
[UsersID] INT NOT NULL DEFAULT 0,
[IsCreatedBy] bit NOT NULL DEFAULT 0

自然地,您会将这些字段从表 A 中取出。如果这些字段丢失,左连接将为您提供 null。

于 2013-12-18T21:48:56.817 回答
1

我认为不可能(在 SQL Server 中)在同一个表上的 2 个或多个 FK 约束上执行它,指向同一个 FK。

通常在这种情况下,您宁愿在逻辑上删除用户,然后在物理上通过引入标志字段(例如 Active 或 Deleted)来删除用户。这样一来,所有关系都保持不变,并且可以进行回顾性分析。--- 彼得

如果您想坚持设置 NULL 的原始想法,解决该问题的一种方法是处理您在存储过程中删除用户并让它在之后立即执行更新。

CREATE PROCEDURE sp_DeleteUser 
    @UserId INT
AS
BEGIN
    SET NOCOUNT ON;

    DELETE FROM Users WHERE Id = @UserId;

    UPDATE News SET created_byId = NULL WHERE created_byId = @UserId;

    UPDATE News SET updated_byId = NULL WHERE created_byId = @UserId;
END
GO
于 2013-01-28T01:41:10.227 回答