2014-07-10 60 views
2

由於太難解釋的原因,我在表中有三列包含日期和時間值。一列僅保存日期,第二列僅保存時間,第三列保存值DATETIME。看起來像這樣:當從NULL更新值時,SQL Server AFTER UPDATE觸發器不工作

OPPORTUNITYID | ... | ProductionDate | ProductionTime | PRODUCTIONDATETIME 
------------------------------------------------------------------------------- 
091798-324971 | ... | 12-07-2014  | 11:30 AM  | 2014-07-12 11:30:00:000 

然後我有一個觸發器,保持這些值同步,無論哪個正在更新。 這是觸發(部分):

CREATE TRIGGER [dbo].[TBL_OPPORTUNITY_DUEDATES_TRU] 
ON [dbo].[TBL_OPPORTUNITY] 
AFTER UPDATE 
AS 

BEGIN 
    SET NOCOUNT ON; 

    IF UPDATE (PRODUCTIONDATETIME) 
    BEGIN 

     UPDATE TBL_OPPORTUNITY 
     SET ProductionDate = CONVERT(VARCHAR(10), PRODUCTIONDATETIME, 105) 
     , ProductionTime = REPLACE(REPLACE(RIGHT('0'+LTRIM(RIGHT(CONVERT(VARCHAR, PRODUCTIONDATETIME,100), 7)), 7), 'AM', ' AM'), 'PM', ' PM') 
     WHERE OPPORTUNITYID IN (SELECT i.OPPORTUNITYID FROM inserted i 
      INNER JOIN deleted d ON i.OPPORTUNITYID = d.OPPORTUNITYID 
      WHERE NOT i.PRODUCTIONDATETIME = d.PRODUCTIONDATETIME 
      AND NOT (i.PRODUCTIONDATETIME = '' OR i.PRODUCTIONDATETIME IS NULL) 
     ); 
    END 

    IF (UPDATE (ProductionDate) OR UPDATE (ProductionTime)) 
    BEGIN 

     UPDATE TBL_OPPORTUNITY 
     SET PRODUCTIONDATETIME = CONVERT(DATETIME, ProductionDate + ' ' + ProductionTime, 105) 
     WHERE OPPORTUNITYID IN (SELECT i.OPPORTUNITYID FROM inserted i 
      INNER JOIN deleted d ON i.OPPORTUNITYID = d.OPPORTUNITYID 
      WHERE (NOT i.ProductionDate = d.ProductionDate 
       OR NOT i.ProductionTime = d.ProductionTime) 
      AND NOT (i.ProductionDate = '' OR i.ProductionDate IS NULL) 
      AND NOT (i.ProductionTime = '' OR i.ProductionTime IS NULL) 
     ); 

     UPDATE TBL_OPPORTUNITY 
     SET PRODUCTIONDATETIME = CONVERT(DATETIME, ProductionDate + ' 12:00:00', 105) 
     WHERE OPPORTUNITYID IN (SELECT i.OPPORTUNITYID FROM inserted i 
      INNER JOIN deleted d ON i.OPPORTUNITYID = d.OPPORTUNITYID 
      WHERE (NOT i.ProductionDate = d.ProductionDate 
       OR NOT i.ProductionTime = d.ProductionTime) 
      AND NOT (i.ProductionDate = '' OR i.ProductionDate IS NULL) 
      AND (i.ProductionTime = '' OR i.ProductionTime IS NULL) 
     ); 

    END 

END 
GO 

觸發按預期工作時的任何值被更新。但是,如果值正在從NULL更新,或者換句話說,列中的舊值爲NULL,並且新值爲(例如'02 -03 -12'),則觸發器將失敗(因爲不會進行任何更改) 2014' 。

這是爲什麼?

服務器是Microsoft SQL Server 2008 R2。

謝謝你的任何線索。

+0

如果更新將所有3列更改爲不一致的值,您打算如何處理?哪些值是「正確的」? –

+1

這絕不會發生,因爲值是從不同的來源改變的 - 一個來源只改變「組分」值,另一個來源只改變「合成」值。 –

回答

1

在寫入時,觸發器必須忽略舊值爲NULL的行,因爲涉及NULL的等式或不等式永遠無法計算爲true。 WHERE條件如NOT i.ProductionDate = d.ProductionDate永遠不會返回任何行,如果d.ProductionDate爲NULL,無論i.ProductionDate是什麼。您需要明確檢查d.ProductionDate IS NULL處理d.ProductionDate無價值情況的可能性。

+0

所以你說'NOT something = NULL'總是評估爲false? –

+0

'NOT(something = NULL)'呢? –

+0

@ igor-sinkovec'NOT something = NULL'和'NOT(something = NULL)'都等價於一些不等於NULL和NULL的東西。它永遠不會評價爲真。請參閱http://msdn.microsoft.com/en-us/library/ms188795(v=sql.105)。重要的部分是:'當一個或兩個參數都爲NULL時,比較運算符返回UNKNOWN – Muqo

0

這樣做對每一列要跟蹤

DECLARE @ProductionDate Date;  
    DECLARE @ProductionDateOld Date; 
    DECLARE @ProductionDateInd bit = 0; // you can use the indicator later to determine which field changed. if = 0 it didn't change, if 1 it did change 
    DECLARE @ProductionDateTime DateTime;  
    DECLARE @ProductionDateTimeOld DateTime; 
    DECLARE @ProductionDateTimeInd bit = 0; 

    SELECT @ProductionDate=ProductionDate FROM inserted i; 
    SELECT @ProductionDateOld = d.ProductionDate FROM deleted d; 
    if @ProductionDateOld <> @ProductionDate 
     @ProductionDateInd = 1; 
    if @ProductionDateOld IS NULL AND @ProductionDate IS NOT NULL 
     @ProductionDateInd = 1; 

SELECT @ProductionDateTime=ProductionDateTime FROM inserted i; 
SELECT @ProductionDateTimeOld = d.ProductionDateTime FROM deleted d; 
if @ProductionDateTimeOld <> @ProductionDateTime 
    @ProductionDateTimeInd = 1; 
if @ProductionDateTimeOld IS NULL AND @ProductionDateTime IS NOT NULL 
    @ProductionDateTimeInd = 1; 

然後檢查是否值改變(我這樣做是爲了只寫歷史/審計表,如果有確實是一個變化)

if (@ProductionDateInd = 1 OR 
@ProductionDateInd = 1) 

INSERT INTO TBL_OPPORTUNITY_DUEDATES_TRU (
ProductionDate, 
ProductionDateInd, 
ProductionDateTime, 
ProductionDateTimeInd, 
. 
. 
. 
) 

VALUES (
@ProductionDate, 
@ProductionDateInd, 
@ProductionDateTime, 
@ProductionDateTimeInd, 
. 
. 
. 
)