【问题标题】:How to emulate a BEFORE DELETE trigger in SQL Server 2005如何在 SQL Server 2005 中模拟 BEFORE DELETE 触发器
【发布时间】:2011-06-08 01:08:56
【问题描述】:

假设我有三个表,[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] 值。这是真的?如果是这样,我怎样才能实现我的目标?

我想我需要将 FK 加入 [TWO] 更改为 [ONE_TWO] 以不使用级联,并在手动删除 [TWO] 之前在触发器中手动删除 [ONE_TWO]记录。但如果有更简单的方法,我宁愿不经历所有这些。

【问题讨论】:

    标签: sql sql-server sql-server-2005 tsql triggers


    【解决方案1】:

    您可以使用 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
    

    【讨论】:

    • 这行得通,但我的情况和您提供的测试之间的区别是我的表有外键作为约束,这一切都不同。创建表 [one_two] (one_id int, two_id int); ALTER TABLE [dbo].[one_two] 添加约束 [FK_one_two__one_oneid] 外键([one_id])引用 [dbo].[one] ([one_id]) ON DELETE CASCADE; ALTER TABLE [dbo].[one_two] 添加约束 [FK_one_two__two_twoid] 外键([two_id]) 引用 [dbo].[two] ([two_id]) ON DELETE CASCADE;此更改会导致测试失败。
    • Mark,"two_id int references two(two_id)" 是创建 FK 引用两个(two_id)的快捷方式。它与您的代码完全相同,只是您为 one_id 和 two_id 分别创建了一个。知道了这一点,我还是测试了你的版本,它仍然有效。试一试。
    • 昨天当我用这些替换运行脚本时,我收到了 547 错误。我又做了一次,效果很好。我一定是打错了什么。感谢您的帮助!
    猜你喜欢
    • 2023-04-07
    • 1970-01-01
    • 2012-04-17
    • 1970-01-01
    • 1970-01-01
    • 2014-11-11
    • 1970-01-01
    • 2013-05-25
    • 2010-09-14
    相关资源
    最近更新 更多