目标是阻止新值与旧值相同的行的更新(因为该表具有我不想重置的自动更新时间戳)。
问题是某些列可以为空,因此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)
)
有更好的方法吗?
答案 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。