Search code examples
sql-servermergenull

Nulls and the MERGE statement: I need to set a value to infinity. How?


In SQL Server with a MERGE code, everything is fine except when there are 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). 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';

Solution

  • In SQL Server 2022 you can use

    WHEN MATCHED AND tgt.C IS DISTINCT FROM src.C
    

    In previous versions you can use

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

    The second version can still be more compact if you need to do this check across multiple columns.

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

    See this article for more on this issue.