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

时间:2013-11-22 20:38:55

标签: sql-server tsql 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() 

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

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

我是否遗漏了一些愚蠢明显地盯着我的东西,这是绕过我的WHERE条款?

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

CASEMASTER.HOLDLETTERUNTIL是DATE字段。

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

CASEMASTER&gt; EVENTMASTER是1-N
EVENTMASTER&gt; EVENTLIBRARY是N-1

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

1 个答案:

答案 0 :(得分:6)

不确定EVENTID与任何内容有什么关系,因为我根本没有看到查询中提到的EVENTID。也许你加入了比你想象的更多的行,因为你遗漏了一个连接条件 - 我认为EVENTLIBRARY中至少有一行HOLDLETTERS = 1,即使它有不同的EVENTID比正在更新的当前行,或者与查询中提到的行不同DEFINITIONID。我不知道实际的查询应该是什么,因为我没有架构和表间关系。

此外:

UPDATE C SET HOLDLETTERSUNTIL = '1/1/9999' 
     --^-- this...
FROM cases.CASEMASTER C --<-- ...should match this

最后,您假设触发器仅在实际影响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;

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

See?

(0 row(s) affected)

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

IF EXISTS (SELECT 1 FROM inserted)

和/或

IF EXISTS (SELECT 1 FROM deleted)

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

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

更新:

  

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

这绝对是会发生的事情,而且绝对不是新事物。从the SQL Server 2005 documentation for CREATE TRIGGER, last updated in July of 2006中的第一个音符开始:

  

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