2013-11-22 76 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