【问题标题】:Delete records of table which has 2 foreign keys that reference to same table删除具有 2 个引用同一个表的外键的表的记录
【发布时间】:2022-08-18 14:46:56
【问题描述】:

我有两张桌子,第一张是隔间第二个是上隔间.请看下文。上面的隔间有 2 列,它们是外键并引用隔间表。当我将删除和更新操作设置为 2 个外键的级联时,我收到以下错误。

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

下面的 CompId 和 AboveCompId 是外键和对 Compartment 表的引用。我应该按照哪种方式添加删除级联?我使用了下面的触发器,但它也没有工作,并在下面添加了错误。

车厢上方

隔间

扳机

ALTER TRIGGER [dbo].[delFromCompartment] on [dbo].[Compartment]
    FOR DELETE
AS
    DELETE FROM dbo.AboveCompartment
    WHERE CompId IN(SELECT deleted.Id FROM deleted)

错误

标签: sql sql-server triggers foreign-keys cascade


【解决方案1】:

您不能使用级联来实现这一点,因为 SQL Server 不允许您这样做。

您也不能使用触发器来实现它,因为外键是强制执行的你到了触发器。

您需要编写一个存储过程,首先删除父表行,然后删除子表

CREATE OR ALTER PROCEDURE dbo.Delete_Compartment
  @CompartmentId int
AS

SET XACT_ABORT, NOCOUNT ON;   -- always use XACT_ABORT if you have a transaction

BEGIN TRAN;

DELETE AboveCompartment
WHERE CompId = @CompartmentId;

DELETE AboveCompartment
WHERE AboveCompId = @CompartmentId;

DELETE Compartment
WHERE Id = @CompartmentId;

COMMIT;

我必须说,这个桌子的设计有些可疑。 AboveCompId 作为列名意味着它代表多个孩子的单个父母,而不是多个孩子的多个父母。

如果是这样,那么您应该将其实现为自引用外键。删除 AboveCompartment 表,并添加一列

ALTER TABLE Compartment
  ADD AboveCompId int NULL REFERENCES Compartment (Id);

这个外键不能级联。但是现在删除只在一个表上,但您可以以递归方式进行。只要你一次删除所有行,你就不应该有外键冲突的问题。

CREATE OR ALTER PROCEDURE dbo.Delete_Compartment
  @CompartmentId int
AS

SET NOCOUNT ON;

-- no transaction needed as it's one statement

WITH cte AS (
    SELECT @CompartmentId AS Id

    UNION ALL

    SELECT c.Id
    FROM Compartment c
    JOIN cte ON cte.Id = c.AboveCompId;
)
DELETE c
FROM Compartment c
JOIN cte ON cte.Id = c.Id;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多