【发布时间】:2020-05-08 19:22:24
【问题描述】:
我的一个触发器发生了一些奇怪的事情。我已经构建了一个触发器,它将检查用户是否正在尝试UPDATE 或DELETE 表中具有[Released_Flag] = 'Y' 的行,如果是这种情况则回滚事务。但是,如果用户尝试将 Released_Flag 字段从“N”更新为“Y”,它仍然会返回错误。
我的触发器是:
CREATE TRIGGER [dbo].[Prevent_Delete] ON [dbo].[Data_Test]
AFTER DELETE, UPDATE
AS
BEGIN
SET NOCOUNT ON
DECLARE @Release_Flag char(1)
SELECT @Release_Flag = [Release_Flag] FROM deleted
IF @Release_Flag='Y'
BEGIN
RAISERROR('Cannot update or delete a RELEASED variable.',16,1)
ROLLBACK
END
END
以上导致UPDATE 语句中的一些问题。它有时会引发错误,即使正在更新的行具有 Release_Flag = 'N'。知道为什么会发生这种情况吗?
我还在触发器中使用了SELECT * FROM [deleted] 来查看发生了什么,尽管[deleted] 表中的某些行显示 Release_Flag = 'Y',尽管它们实际上是 'N'。
【问题讨论】:
-
应该是
BEFORE DELETE -
您是否还需要处理多次删除?如果一次删除多个记录会怎样?这段代码会出错
-
您正在将一个变量设置为 Released_flag 的值,但正如您所说,当您从已删除的表中选择时,您会得到多行。因此,该变量的值可以来自已删除表中的任何行。触发器在整个过程中触发,而不仅仅是一行。此触发器仅适用于个别更新或删除。
-
您的代码存在一个非常常见的缺陷——您假设只有一行受到更新/删除/合并语句的影响(并且存在于虚拟插入表中)。修复它 - 在互联网上搜索有关如何做到这一点的讨论。这可能会解决您遇到的问题,但没有很难知道的MVCE。
-
以后,我还建议您使用 SET 语句来分配标量值,如果这是您在使用查询时的期望。如果违反该假设,它将生成语法错误,提醒您(或使用您的应用程序的人)发生了严重错误。当您使用 select 语句进行赋值时,其中一行将用于赋值,但您无法保证是哪一行。您可能认为存在基于简单测试的模式,但不能保证。
标签: sql-server tsql database-trigger