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 sinkovecnotsomething=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,
.
.
.
)