2014-07-10 37 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, 
. 
. 
. 
)