2013-11-22 87 views
1

运行在SQL Server 2008 R2,这里是我的UPDATE语句,这是在一个正在运行后INSERT触发器:想不通为什么这个UPDATE语句运行

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,我不能为我的生活算出为什么这是更新caseCASEMASTER中的任何行。但事实上我知道这是事实,因为它正在触发该桌上的触发器。

我是否错过了一些愚蠢的明显盯着我的脸,那是绕过我的WHERE子句?

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

CASEMASTER.HOLDLETTERUNTIL是日期字段。

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

CASEMASTER> EVENTMASTER为1-N
EVENTMASTER> EVENTLIBRARY为N-1

而且,现在我真的很困惑!它触发了第二个触发器。但是第二个触发器的INSERTED表中有ZERO行。所以看起来,Sql Server仅仅因为触发事件被触发就触发了一个触发器,即使没有实际的行被改变?这是新东西吗?我总是假设如果没有行被更改,那么AFTER UPDATE触发器将不会触发。

+0

它实际上更新与新值记录哪些条件是错误的? –

+0

你告诉我们没有'events.EVENTLIBRARY.HOLDLETTERS = 1'的行,但查询更新'cases.CASEMASTER'表中的一些行吗? –

+0

是的,我手动使用硬编码值的单行插入测试它。而且我特别使用了一个EVENTID,其中HOLDLETTERS = 0,但它正在更新cases.CASEMASTER。我完全困惑不解。 – eidylon

回答

5

不知道什么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) 

Y我们的第二个触发器在宣布它已经解雇之前可能不会做那样的事情。

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

UPDATE:

如此看来,Sql Server的触发仅仅是因为触发事件运行触发器,即使没有行实际上改变了吗?这是新东西吗?

这绝对是发生了什么,它绝对不是新的。从最初的音符the SQL Server 2005 documentation for CREATE TRIGGER, last updated in July of 2006

当任何有效的事件被激发,无论任何表行是否会受到影响,这些触发火灾。这是设计。

+0

AHHH - 好的,你刚刚回答了我更新的问题。即使没有行实际受到影响,触发器也会触发。这对我来说似乎很奇怪,但是......它就是这样。现在我只需要重新编码来解决这个问题。谢谢!!! – eidylon

+0

这就是为什么SQL Server UPDATE触发器会为您提供基于您的过程的伪表/ INSERTED/DELETED。一个空的INSERTED表(零行)可能是你需要加快速度的容易实现的快速返回。在某些情况下,INSERTED表上的游标(可能连接到其他表)会比当前方法中使用的单一UPDATE语句提供更好的性能。 – hardmath