【问题标题】:Two foreign keys on same table: how to implement on delete cascade?同一张表上的两个外键:如何实现删除级联?
【发布时间】:2019-05-14 14:51:01
【问题描述】:

我有一个有两列的表。它们中的每一个都是同一个第二个表的外键:

CREATE TABLE [dbo].[TBL_TOGETHER]
(
    [ID1] [int] NULL FOREIGN KEY REFERENCES [TBL_ANOTHER_TABLE](ID),
    [ID2] [int] NULL FOREIGN KEY REFERENCES [TBL_ANOTHER_TABLE](ID)
)

但现在我不能再从TBL_ANOTHER_TABLE 中删除实体了:

DELETE 语句与 REFERENCE 约束“FK__TBL_ASD__4DE98D56”冲突。

我的问题是:在TBL_TOGETHER 实施ON DELETE CASCADE 的最佳解决方案是什么?

我尝试在外键上添加ON DELETE SET NULLON DELETE CASCADE,但由于循环或多个级联路径,它不起作用。

我曾尝试在TBL_ANOTEHR_TABLE 上添加删除触发器,但仍与外键冲突:

ALTER TRIGGER REMOVE_FORENGKEY
ON TBL_ANOTHER_TABLE 
FOR DELETE
AS
BEGIN
    UPDATE TBL_TOGETHER
    SET TBL_TOGETHER.ID1 = NULL
    FROM TBL_TOGETHER
    JOIN deleted ON TBL_TOGETHER.ID1 = deleted.ID;

    UPDATE TBL_TOGETHER
    SET TBL_TOGETHER.ID2 = NULL
    FROM TBL_TOGETHER
    JOIN deleted ON TBL_TOGETHER.ID2 = deleted.ID;
END

我尝试了INSTEAD OF DELETE-trigger,但这种方法也不起作用,因为引用的表还包含具有级联约束的外键。

ALTER TRIGGER REMOVE_FORENGKEY
ON TBL_ANOTHER_TABLE 
INSTEAD OF DELETE
AS
BEGIN
    UPDATE TBL_TOGETHER
    SET TBL_TOGETHER.ID1 = NULL
    FROM TBL_TOGETHER
    JOIN deleted ON TBL_TOGETHER.ID1 = deleted.ID;

    UPDATE TBL_TOGETHER
    SET TBL_TOGETHER.ID2 = NULL
    FROM TBL_TOGETHER
    JOIN deleted ON TBL_TOGETHER.ID2 = deleted.ID;

    DELETE TBL_ANOTHER_TABLE 
    FROM TBL_ANOTHER_TABLE 
    JOIN deleted ON TBL_ANOTHER_TABLE.ID = deleted.ID 
    WHERE TBL_ANOTHER_TABLE.ID = deleted.ID;
END

错误:

无法更改表 'TBL_ANOTHER_TABLE' 上的 INSTEAD OF DELETE 或 INSTEAD OF UPDATE TRIGGER 'REMOVE_FORENGKEY'。这是因为该表有一个 FOREIGN KEY 和级联 DELETE 或 UPDATE。

【问题讨论】:

  • SQL Server 仅支持单个级联。如果两者都很重要,则需要以与使用 CASCADE 不同的方式来处理此问题,例如代替触发器,或强制用户使用 SP 完成删除,从而优雅地处理删除语句。
  • 如果你想在一个而不是触发器中管理删除,你应该从外键中删除级联。
  • 我不想从引用的 TBL_ANOTHER_TABLE 中删除级联,因为它也会在级联时自动删除。
  • 但是您正试图在而不是触发器中处理级联部分。你不能两者都做。这就是错误消息清楚地告诉您的内容。
  • 如果你想使用CASCADE,那么你必须选择1个键来处理级联,然后不允许人们删除会影响另一个“树”的行;可能会使键上的级联点无效。如果您想使用INSTEAD OF 触发器,那么就像@SeanLange 所说,您必须对所有事情都使用触发器;你不能混合这两种解决方案。如果您可以控制用户,那么我个人会选择 SP 路线,否则将采用代替触发器的方式。

标签: sql-server foreign-keys ddl


【解决方案1】:

使用这个触发器: 此触发器起作用而不是删除。因此,您必须在设置对 null 的引用后删除记录。

 CREATE TRIGGER Trigger_TBL_ANOTHER_TABLE
    ON [dbo].[TBL_ANOTHER_TABLE]
    INSTEAD OF DELETE
    AS 
    BEGIN

        SET NOCOUNT ON;

        UPDATE  t
        SET     t.ID1 = NULL
        from [dbo].[TBL_TOGETHER] t inner join
        deleted d on d.ID = t.ID1

        UPDATE  t
        SET     t.ID2 = NULL
        from [dbo].[TBL_TOGETHER] t inner join
        deleted d on d.ID = t.ID2

        DELETE  t
        from [dbo].[TBL_ANOTHER_TABLE] t inner join
        deleted d on d.ID = t.ID

    END
    GO

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多