无法弄清楚为什么这个UPDATE语句正在运行

eid*_*lon 2 t-sql sql-server join sql-server-2008-r2 sql-update

在Sql Server 2008 R2中运行,这是我的UPDATE语句,它在AFTER INSERT触发器中运行:

UPDATE cases.CASEMASTER
SET    HOLDLETTERSUNTIL = '1/1/9999'
FROM   cases.CASEMASTER C
       JOIN INSERTED I
         ON I.CASEID = C.ROWID
       JOIN events.EVENTLIBRARY L
         ON L.ROWID = I.DEFINITIONID
WHERE  L.HOLDLETTERS = 1
       AND C.HOLDLETTERSUNTIL < GETDATE() 
Run Code Online (Sandbox Code Playgroud)

连接都是正确的,并且通过输出窗口,我已经确认where条件评估 - 按顺序 - 为FALSE和TRUE.

但由于某些原因我无法理解,这个声明实际上正在运行并试图触发UPDATE.由于第一个WHERE条件为FALSE,我不能为我的生活中的数字,为什么这是更新case.CASEMASTER中的任何行.但我知道事实是因为它正在触发该桌子上的触发器.

我错过了一些愚蠢地盯着我看的东西,那是绕过我的WHERE条款吗?

EVENTLIBRARY.HOLDLETTERS是一个INT字段,可以是-1,0或1,指定特定事件在针对案例记录时是否应该是UNHOLD,NOTCHANGE或HOLD字母.

CASEMASTER.HOLDLETTERUNTIL是DATE字段.

插入的表是EVENTMASTER,它定义了针对案例记录的实际事件.

CASEMASTER> EVENTMASTER是1-N
EVENTMASTER> EVENTLIBRARY是N-1

而且,现在我真的很困惑!它正在解雇第二个触发器.但是第二个触发器的INSERTED表中有ZERO行.所以似乎Sql Server只是因为触发事件被运行而触发了一个触发器,即使没有实际更改行?这是新的东西吗?我总是假设如果没有更改行,则AFTER UPDATE触发器不会触发.

Aar*_*and 6

不知道是什么EVENTID与任何东西有关,因为我根本没有EVENTID在查询中看到提到.也许你要加入更多的行比你想象的,因为你已经离开了加盟条件-我相信至少有一排EVENTLIBRARYHOLDLETTERS = 1,即使它有不同的EVENTID比当前行(S)被更新,或不同的DEFINITIONID比您查询中提到的那个.我不知道实际的查询应该是什么,因为我没有架构和表间关系.

也:

UPDATE C SET HOLDLETTERSUNTIL = '1/1/9999' 
     --^-- this...
FROM cases.CASEMASTER C --<-- ...should match this
Run Code Online (Sandbox Code Playgroud)

最后,您假设触发器仅在实际影响1行或更多行时触发,这是假的.即使没有实际影响的行,也会触发每个相关语句的触发器.简单的例子:

USE tempdb;
GO

-- simple, empty table:

CREATE TABLE dbo.flab(i INT);
GO

-- simple table that just prints a message:

CREATE TRIGGER dbo.trFlab
ON dbo.flab FOR UPDATE
AS
BEGIN
  SET NOCOUNT ON;

  PRINT 'See?';
END
GO

-- this query affects zero rows, both because the WHERE condition is false
-- and also because there are are no rows in the table to begin with!

UPDATE dbo.flab SET i = 1 WHERE 1 = 2;
Run Code Online (Sandbox Code Playgroud)

但结果显示触发器被触发:

See?

(0 row(s) affected)
Run Code Online (Sandbox Code Playgroud)

通常,您通过以下方式检查触发器中是否实际影响了任何行:

IF EXISTS (SELECT 1 FROM inserted)
Run Code Online (Sandbox Code Playgroud)

和/或

IF EXISTS (SELECT 1 FROM deleted)
Run Code Online (Sandbox Code Playgroud)

在宣布它被解雇之前,你的第二个触发器可能没有做那样的事情.

因此,您应该检查以查看这些行是否已更新,而不是跳到因为在第二个表上触发了触发器而更新行的结论.除非你的连接条件错误(我怀疑那里有些东西是可疑的,因为你在代码中没有提到的评论中提到了一个列),我怀疑这不是真的,你认为发生的事情不是什么实际上发生了.

更新:

所以似乎Sql Server只是因为触发事件被运行而触发了一个触发器,即使没有实际更改行?这是新的东西吗?

这绝对是发生的事情,绝对不是新的.从SQL Server 2005文档CREATE TRIGGER第一个注释开始,最后一次更新于2006年7月:

无论是否有任何表行受到影响,触发任何有效事件时都会触发这些触发器.这是设计的.