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 ID
到 T_Order
中的两个 FK。我还为delete and update rules
到cascade
设置了这两种关系,因为我想如果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 约束?
How can I list all foreign keys referencing a given table in SQL Server?
错误:引入FOREIGN KEY约束可能会导致循环或多个级联路径