SQL Server 引入 FOREIGN KEY 约束可能导致循环或多个级联路径

Posted

技术标签:

【中文标题】SQL Server 引入 FOREIGN KEY 约束可能导致循环或多个级联路径【英文标题】:SQL Server Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths 【发布时间】:2019-10-20 20:46:04 【问题描述】:

我有两张桌子:T_User and T_Order

T_User
--------
ID
Name

T_Order 必须是 T_User 的外键

T_Order
--------
ID
FK_UserActionOwnerID
FK_UserActionReceiverID

然后我在我的图表上建立了两个关系,从 T_User IDT_Order 中的两个 FK。我还为delete and update rulescascade 设置了这两种关系,因为我想如果T_User 记录将被删除,因此T_Order 中的记录应该被删除,或者T_User ID 会改变然后也在@ 中更新它987654336@ 不过我得到以下错误:

'T_User'表保存成功'T_Order'表 - 无法创建关系“FK_T_Order_T_Users1”。在表 'T_Order' 上引入 FOREIGN KEY 约束 'FK_T_Order_T_Users1' 可能 导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。可以 不创建约束或索引。查看以前的错误。

实图: click here

【问题讨论】:

Foreign key constraint may cause cycles or multiple cascade paths?的可能重复 @MartinBrown 我读到了,但老实说我不知道​​如何解决这个问题。就像 T_Order 有关于谁制作了 Order FK_UserActionOwnerID 的信息,但也有对谁的引用,这意味着我需要两个外键。还可以删除/更新 cascae。如果我无法从一张表到另一张表进行两次引用,该如何解决? 通常的方法是首先创建没有级联的 FK 约束,然后创建触发器以按照您希望的方式进行级联。 @MartinBrown 我上传了图表截图 - 看那里我用红线标记了我还想做什么,但它引发了我描述的错误。 所以你是说你不知道如何在图表设计器中创建没有级联的外键? 【参考方案1】:

@Martin-Brown 链接到的Foreign key constraint may cause cycles or multiple cascade paths? 问题建议使用触发器而不是级联外键。这是一个使用INSTEAD OF DELETE 触发器来做(我认为)你想做的事情的例子。

-- Create tables
create table dbo.T_User (
    ID int identity not null primary key,
    Name varchar(100) not null
)

create table dbo.T_Order (
    ID int identity not null primary key,
    FK_UserActionOwnerID int not null,
    FK_UserActionReceiverID int not null
)
go

-- Create foreign keys
alter table dbo.T_Order add constraint FK_T_Order_T_Users1 FOREIGN KEY (FK_UserActionOwnerID) REFERENCES dbo.T_User (ID) 
alter table dbo.T_Order add constraint FK_T_Order_T_Users2 FOREIGN KEY (FK_UserActionReceiverID) REFERENCES dbo.T_User (ID) 
go

-- Create trigger
create trigger tr_T_User_Delete on dbo.T_User instead of delete as
begin

    if (@@rowcount = 0) return

    delete o from dbo.T_Order o inner join deleted d on d.ID = o.FK_UserActionOwnerID

    delete o from dbo.T_Order o inner join deleted d on d.ID = o.FK_UserActionReceiverID

    delete u from dbo.T_User u inner join deleted d on d.ID = u.ID  

end
go

-- Demo
insert dbo.T_User (Name) values ('Peter'), ('Paul') -- Assume identity ID 1 and 2

insert dbo.T_Order (FK_UserActionOwnerID, FK_UserActionReceiverID) values (1, 1), (1, 2), (2, 2)

select * from dbo.T_Order

delete from dbo.T_User where ID = 1

select * from dbo.T_Order

您可以以相同的方式使用INSTEAD OF UPDATE 触发器,但您可能想考虑一下更新 ID 是否有意义 - 我通常不会想到这一点。

【讨论】:

T_Order 和 T_OrderItem 呢?我是否应该保留这些表之间的连接,因为它意味着删除/更新规则作为级联? @Eldorado 是的,您可以使用 T_Order 和 T_OrderItem 之间的级联规则保留 FK,或者使用上面的触发器 - 这取决于您。 我收到此错误(在我将所有更新/删除删除为“无操作”之前,所以我不明白为什么会出现此错误::tr_T_User_Delete,第 1 行 [Batch Start Line 2] 无法创建 INSTEAD OF表 'T_Users' 上的 DELETE 或 INSTEAD OF UPDATE TRIGGER 'tr_T_User_Delete2'。这是因为表有一个 FOREIGN KEY 和级联 DELETE 或 UPDATE。 @Eldorado 这个错误很明显 - 你不能在同一张表上拥有一个 INSTEAD OF ... 触发器以及具有级联操作的外键。一个或另一个,而不是两者。 我不得不从头开始重新创建这两个表,然后我再次创建它们并运行您的触发器脚本 - 现在它可以工作了。尽管如此,我现在看不到图表上这两个表之间的关系 - 我明白,因为现在没有外键,只有外部触发器。我在这里看到一个问题,让我们想象一下外部应用程序,并假设有人添加了用户的 id 以便不存在。由于我们没有 fks,所以有可能,有什么解决方法吗?

以上是关于SQL Server 引入 FOREIGN KEY 约束可能导致循环或多个级联路径的主要内容,如果未能解决你的问题,请参考以下文章

如何找出引用 SQL Server 中表的 FOREIGN KEY 约束?

“引入 FOREIGN KEY 约束”

How can I list all foreign keys referencing a given table in SQL Server?

错误:引入FOREIGN KEY约束可能会导致循环或多个级联路径

引入 FOREIGN KEY 约束可能会导致循环或多个级联路径 - 为啥?

sql sql__foreign_key.sql