T-SQL INSTEAD OF DELETE 触发器在没有“挑衅”的情况下触发

Posted

技术标签:

【中文标题】T-SQL INSTEAD OF DELETE 触发器在没有“挑衅”的情况下触发【英文标题】:T-SQL INSTEAD OF DELETE Trigger fires without 'provocation' 【发布时间】:2012-02-06 21:32:56 【问题描述】:

我有以下 INSTEAD OF DELETE 触发器,它会在回滚任何删除尝试时发送一封电子邮件。

ALTER TRIGGER tr_OnDel_Orders
ON  ORDERS 
INSTEAD OF DELETE
AS 
BEGIN

SET NOCOUNT ON;

declare @b varchar(5000)
Declare @OrderID BIGINT,

SELECT @OrderID  = OrderID
FROM deleted d

set @b = 'Someone attempted to delete the following order:' + CHAR(10);
set @b = @b + ' OrderID: ' + cast(@OrderID as varchar(30)) + CHAR(10);
set @b = @b + ' UserID: ' +  SYSTEM_USER

RAISERROR('Cannot delete order', 16, 1)
ROLLBACK TRAN

EXEC msdb.dbo.sp_send_dbmail @recipients = 'myemail@mycompany.com',
                         @body = @b,
                         @subject = 'Attempt to Delete an order' 


RETURN
END
GO

当我尝试从 ORDERS 表中删除订单时,此方法有效。但是,我不明白为什么,这个触发器会定期发送带有空正文的电子邮件。据我所知,没有明显的尝试删除订单。还有什么可能导致这样的空白电子邮件?

【问题讨论】:

此触发器不适用于行集,你知道吗?另外,orders 有带有删除级联选项的外键吗? 也许它会在某人执行delete orders where 1=0 时触发,而@OrderID 最终会变成null。我想那也会使 @b 为空。 只有一种方法可以找到:SQL Profiler。 您可以设置扩展事件跟踪以在触发器触发时捕获 TSQL 调用堆栈Example code here 【参考方案1】:

此触发器处理多行删除,并且如果有人触发不删除任何行的删除语句,也不会向您发送无意义的电子邮件:

ALTER TRIGGER dbo.tr_OnDel_Orders
ON dbo.ORDERS 
INSTEAD OF DELETE
AS 
BEGIN
  IF EXISTS (SELECT 1 FROM deleted)
  BEGIN
    SET NOCOUNT ON;

    DECLARE @b VARCHAR(5000) = '';

    SELECT @b = @b + ',' + CONVERT(VARCHAR(12), OrderID)
        FROM deleted;

    SET @b = 'Someone attempted to delete the following orders:' 
        + CHAR(10) + @b + CHAR(10) + ' UserID: ' +  SYSTEM_USER;

    ROLLBACK TRANSACTION; -- should probably check @@TRANCOUNT first!

    EXEC msdb.dbo.sp_send_dbmail 
         @recipients = 'myemail@mycompany.com',
         @body = @b,
         @subject = 'Attempt to Delete an order';

    RAISERROR('Cannot delete order(s)', 16, 1);
  END

  RETURN;
END
GO

【讨论】:

【参考方案2】:

关于触发器的最常见错误是它们通常被创建,因为它们将为每个删除的记录工作一次。

但是如果使用一条 DELETE 语句删除了超过 1 条记录,则触发器应该能够按照 Aaron 的建议处理所有已删除的记录。

避免在触发器中使用单值变量很重要,开发人员应在触发器中构建基于集合的解决方案

【讨论】:

以上是关于T-SQL INSTEAD OF DELETE 触发器在没有“挑衅”的情况下触发的主要内容,如果未能解决你的问题,请参考以下文章

Performance - Inefficient use of keySet iterator instead of entrySet iterator

xlwings: Write Excel macro using python instead of VBA

PostCSS received undefined instead of CSS string

[ES2015] Number.isNaN instead of isNaN

[React] When to useReducer instead of useState

SQL Server INSTEAD OF INSERT 触发器失败