假设我有三个表:[ONE]、[ONE_TWO] 和 [TWO]。 [ONE_TWO] 是一个多对多连接表,仅包含 [ONE_ID 和 [TWO_ID] 列。设置了外键来链接 [ONE] 到 [ONE_TWO] 和 [TWO] 到 [ONE_TWO]。 FK 使用 ON DELETE CASCADE 选项,因此如果删除 [ONE] 或 [TWO] 记录,关联的 [ONE_TWO] 记录也将自动删除。
我想在 [TWO] 表上有一个触发器,这样当删除 [TWO] 记录时,它会执行一个存储过程,该存储过程采用 [ONE_ID] 作为参数,传递链接的 [ONE_ID] 值删除之前的 [TWO_ID]:
DECLARE @Statement NVARCHAR(max)
SET @Statement = ''
SELECT @Statement = @Statement + N'EXEC [MyProc] ''' + CAST([one_two].[one_id] AS VARCHAR(36)) + '''; '
FROM deleted
JOIN [one_two] ON deleted.[two_id] = [one_two].[two_id]
EXEC (@Statement)
显然,我需要一个 BEFORE DELETE 触发器,但 SQL Server 2005 中没有这样的东西。由于级联 FK,我无法使用 INSTEAD OF 触发器。
我的印象是,如果我使用 FOR DELETE 触发器,当我将 [deleted] 连接到 [ONE_TWO] 以查找 [ONE_ID] 值列表时,FK 级联将已经删除了关联的 [ONE_TWO] 记录,因此我永远找不到任何 [ONE_ID] 值。这是真的?如果是这样,我怎样才能实现我的目标?
我认为我需要将连接 [TWO] 的 FK 更改为 [ONE_TWO],以不使用级联,并在手动删除 [TWO] 之前在触发器中手动删除 [ONE_TWO]记录。但如果有更简单的方法,我宁愿不经历所有这些。
最佳答案
您可以使用 INSTEAD OF 触发器。它在实际删除之前(替换)触发,因此 [one_two] 中的链接记录必须仍然存在。
create table [one] (one_id int not null primary key)
create table [two] (two_id int not null primary key)
create table [one_two] (one_id int, two_id int references two(two_id) on delete cascade)
GO
CREATE trigger t_del_two
on two
instead of delete
as
begin
SET NOCOUNT ON
DECLARE @Statement NVARCHAR(max)
SET @Statement = ''
SELECT @Statement = @Statement + N'EXEC [MyProc] ''' + CAST([one_two].[one_id] AS VARCHAR(36)) + '''; '
FROM deleted
JOIN [one_two] ON deleted.[two_id] = [one_two].[two_id]
PRINT (@Statement)
--EXEC (@Statement)
-- carry out the actual delete
DELETE TWO WHERE two_id in (SELECT two_id from deleted)
end
GO
一些示例值
insert into one select 1
insert into one select 2
insert into one select 3
insert into two select 11
insert into two select 12
insert into two select 13
insert into one_two select 1,11
insert into one_two select 1,13
insert into one_two select 2,13
现在测试一下
delete two where two_id=13
关于sql - 如何在 SQL Server 2005 中模拟 BEFORE DELETE 触发器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4672731/