Nulls and the MERGE statement: I need to set a val

2019-02-08 17:37发布

In SQL Server 2008, I'm using MERGE. Everything is fine except that I have 2 nullable columns. If I pass a null value and the target isn't null, MERGE doesn't see a difference (evals against null = false per BOL). If I use IsNull on both sides (source & target) that works, but has the issue of potentially mis-evaluating a value.

What I mean by the last statement is, if I say:

WHEN MATCHED AND NOT (IsNull(tgt.C, 0) = IsNull(src.C, 0)) THEN

then if tgt.C is null and src.C = 0, no update will be performed. No matter what substitute value I choose, I'll have this problem.

I also tried the "AND NOT (...true...)" syntax since BOL states that evaluations against null result in FALSE. However, it seems they actually result in NULL and do not result in my multi-part statement becoming false.

I thought one solution is to use NaN or -INF or +INF since these are not valid in target. But I can't find a way to express this in the SQL.

Any ideas how to solve this?

EDIT:

The following logic solves the problem, but it's verbose and won't make for fast evals:

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';

8条回答
SAY GOODBYE
2楼-- · 2019-02-08 17:44

You can use

WHEN MATCHED AND EXISTS (SELECT tgt.C EXCEPT SELECT src.C)

See this article for more on this issue.

查看更多
不美不萌又怎样
3楼-- · 2019-02-08 17:48
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
查看更多
\"骚年 ilove
4楼-- · 2019-02-08 17:50

Instead of using 0 when the values are null, why not use a value that is highly unlikely to exist? EG (IsNull(tgt.C, 2093128301).

The datatypes are int so you have a lot to play with......

查看更多
Rolldiameter
5楼-- · 2019-02-08 17:52
WHEN MATCHED AND
(
   NULLIF(tgt.C, src.C) IS NOT NULL OR NULLIF(src.C, tgt.C) IS NOT NULL
)
THEN
查看更多
Animai°情兽
6楼-- · 2019-02-08 18:04

Actually, this works better. Just add another substitution value as an OR :-

WHEN MATCHED AND 
    ( 
    NOT (IsNull(tgt.C, 0) = IsNull(src.C, 0)) OR NOT (IsNull(tgt.C, 1) = IsNull(src.C, 1)) 
    ) 
THEN ....
查看更多
放荡不羁爱自由
7楼-- · 2019-02-08 18:06

Have you tried SET ANSI_NULLS OFF, which will make NULL=NULL return true? This may create additional issues but it could be a script-level workaround (turn it off then on once you run your proc).

查看更多
登录 后发表回答