在SQL Server 2008中,我正在使用MERGE。一切都很好,除了我有2个可以为空的列。如果我传递一个空值并且目标不是null,则MERGE没有看到差异(对每个BOL的ev = null = false)。如果我在两边都使用IsNull(源和目标),但有可能错误评估值的问题。
我的意思是,如果我说:
WHEN MATCHED AND NOT (IsNull(tgt.C, 0) = IsNull(src.C, 0)) THEN
然后如果tgt.C为null且src.C = 0,则不会执行更新。无论我选择什么替代价值,我都会遇到这个问题。
我还尝试了“AND NOT(... true ...)”语法,因为BOL声明对null的评估结果为FALSE。但是,它们似乎实际上导致NULL并且不会导致我的多部分语句变为false。
我认为一种解决方案是使用NaN或-INF或+ INF,因为它们在目标中无效。但我找不到在SQL中表达这种方法的方法。
任何想法如何解决这个问题?
编辑:
以下逻辑解决了这个问题,但它很冗长,不会造成快速逃避:
declare @i int, @j int
set @j = 0
set @i = 0
if ISNULL(@i, 0) != ISNULL(@j, 0) OR
((@i is null or @j is null) and not (@i is null and @j is null))
print 'update';
答案 0 :(得分:19)
答案 1 :(得分:13)
您可以更改合并语句的ON部分,检查源和目标何时为空。
MERGE tgt
USING src
ON ( -- enter non-nullable columns to match on ...
tgt.A = src.A
AND (tgt.C = src.C OR (tgt.C IS NULL AND src.C IS NULL))
)
WHEN MATCHED -- ...
答案 2 :(得分:3)
实际上,这效果更好。只需添加另一个替换值作为OR: -
WHEN MATCHED AND
(
NOT (IsNull(tgt.C, 0) = IsNull(src.C, 0)) OR NOT (IsNull(tgt.C, 1) = IsNull(src.C, 1))
)
THEN ....
答案 3 :(得分:2)
WHEN MATCHED AND tgt.c <> src.c OR tgt.c IS NULL AND src.c IS NOT NULL OR tgt.c IS NOT NULL AND src.c IS NULL
答案 4 :(得分:2)
您是否尝试SET ANSI_NULLS OFF
,这会使NULL=NULL
返回true? This may create additional issues但它可能是一个脚本级别的解决方法(在运行proc之后将其关闭然后再打开)。
答案 5 :(得分:2)
这也有效,如果您想要检查多个列是否不同,可能会更好。
MERGE @t2 a
using @t1 b
ON a.PK = b.PK
WHEN MATCHED AND CHECKSUM(a.PK,a.VALUE)!= CHECKSUM(b.pk,b.VALUE)
THEN UPDATE SET a.VALUE = b.VALUE;
答案 6 :(得分:0)
当值为null时,为什么不使用极不可能存在的值,而不是使用0? EG(IsNull(tgt.C,2093128301)。
数据类型为int,因此您可以使用......
答案 7 :(得分:0)
您可以在ON子句中检查是否为空:
MERGE TargetTable
USING (VALUES (0)) as s(x)
ON last_run is not null
WHEN not matched then
insert (last_run) values(getdate())
when matched then
update set last_run=getDate();
答案 8 :(得分:-1)
WHEN MATCHED AND
(
NULLIF(tgt.C, src.C) IS NOT NULL OR NULLIF(src.C, tgt.C) IS NOT NULL
)
THEN