如何检查可为空的列的新值是否与旧值不同

时间:2018-05-31 16:15:58

标签: sql sql-server sql-server-2012 null sql-update

目标是阻止新值与旧值相同的行的更新(因为该表具有我不想重置的自动更新时间戳)。

问题是某些列可以为空,因此New<> Old不起作用,因为如果New或Old为NULL,则结果为NULL。

解决方法是使用ISNULL,但如果替换值可能是表中的有效值,则不起作用:

UPDATE tableName
SET ColumnName = @newValue
WHERE ISNULL(ColumnName, 'ValueIsNull') <> ISNULL(@newValue, 'ValueIsNull')

我找到的另一种方法是比较值,然后检查XOR New和Old以查看是否为NULL。这不是很清楚,特别是如果你必须检查多个列:

UPDATE tableName
SET ColumnName = @newValue
WHERE
    ColumnName <> @newValue
    OR (
        (ColumnName IS NULL AND @newValue IS NOT NULL)
        OR (ColumnName IS NOT NULL AND @newValue IS NULL)
    )

有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

我喜欢这种方法,因为您可以轻松地同时比较多个列。运行此命令,您将看到它只在您关心的列发生更改时更新行。

DECLARE @T1 TABLE (ID INT, Val1 VARCHAR(20),Val2 VARCHAR(20),LastUpdated DATETIME,VersionNum INT)
DECLARE @Val1 VARCHAR(20)='test'
DECLARE @Val2 VARCHAR(20)='test2'
INSERT INTO @T1 (ID,Val1,Val2,LastUpdated,VersionNum) SELECT 1,@Val1,@Val2,GETDATE(),1

SELECT * FROM @T1

UPDATE @T1
SET Val1=@Val1,Val2=@Val2, LastUpdated=GETDATE(),VersionNum=VersionNum+1
WHERE BINARY_CHECKSUM(Val1,Val2)<>BINARY_CHECKSUM(@Val1,@Val2)

SELECT * FROM @T1

SET @Val1 ='test'
SET @Val2 ='Oooooo'

UPDATE @T1
SET Val1=@Val1,Val2=@Val2, LastUpdated=GETDATE(),VersionNum=VersionNum+1
WHERE BINARY_CHECKSUM(Val1,Val2)<>BINARY_CHECKSUM(@Val1,@Val2)

SELECT * FROM @T1

答案 1 :(得分:0)

这是一招:

UPDATE t
    SET ColumnName = @newValue
    FROM tableName t CROSS APPLY
         (SELECT COUNT(*) as num_values
          FROM (SELECT DISTINCT val
                FROM (VALUES (ColumnName), (@newValue) )  v(val)
               ) v
         ) v
    WHERE num_values <> 1;

SQL Server不支持IS DISTINCT FROM。但是,聚合具有您想要的正确逻辑。如果值相等或两者都是NULL,则计数为1.否则,计数将为0或2。