Triggers 从NULL更新值时SQL Server更新后触发器不工作

Triggers 从NULL更新值时SQL Server更新后触发器不工作,triggers,sql-server-2008-r2,null,Triggers,Sql Server 2008 R2,Null,出于愚蠢的原因,我在一个表中有三列,其中包含日期和时间值。一列只保存日期,第二列只保存时间,第三列保存DATETIME值。看起来像这样: OPPORTUNITYID | ... | ProductionDate | ProductionTime | PRODUCTIONDATETIME ------------------------------------------------------------------------------- 091798-324971 | ... | 12-0

出于愚蠢的原因,我在一个表中有三列,其中包含日期和时间值。一列只保存日期,第二列只保存时间,第三列保存
DATETIME
值。看起来像这样:

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-2014”,则触发器将失败(如中未进行任何更改)

为什么呢

服务器是Microsoft SQL server 2008 R2


感谢您提供的任何线索。

在编写过程中,触发器必须忽略旧值为NULL的行,因为涉及NULL的等式或不等式永远不能计算为true。如果d.ProductionDate为NULL,则诸如
NOT i.ProductionDate=d.ProductionDate
之类的WHERE条件永远不会返回任何行,无论i.ProductionDate是什么。您需要明确检查
d.ProductionDate为NULL的可能性
,以处理d.ProductionDate没有值的情况。

对跟踪的每一列执行此操作

    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; 

如果更新将所有3列更改为不一致的值,您打算怎么做?哪些值是“正确的”?这永远不会发生,因为这些值是从不同的源更改的-一个源只更改“组件”值,另一个源只更改“复合”值。所以你是说
notsomething=NULL
总是计算为false?那么
NOT(something=NULL)呢
?@igor sinkovec
notsomething=NULL
NOT(something=NULL)
都相当于something和NULL之间的不等式。它永远不会被认为是真的。请看。重要的部分是:
当其中一个或两个参数都为NULL时,比较运算符返回UNKNOWN。
if (@ProductionDateInd = 1 OR
@ProductionDateInd = 1)

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

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