Nulls и оператор MERGE: мне нужно установить значение в бесконечность. Как?

В SQL Server 2008 я использую MERGE. Все в порядке, за исключением того, что у меня есть 2 столбца с нулевым значением. Если я передаю нулевое значение, а цель не равна нулю, MERGE не видит разницы (имеет значение null = false для BOL). Если я использую IsNull с обеих сторон (источник и цель), который работает, но имеет проблему потенциально неправильной оценки значения.

Что я подразумеваю под последним утверждением, если я говорю:

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

то если tgt.C равно null и src.C = 0, обновление не будет выполнено. Независимо от того, какое заменимое значение я выбираю, у меня будет эта проблема.

Я также попробовал синтаксис "AND NOT (... true...)", поскольку BOL заявляет, что оценки против нулевого результата в FALSE. Однако кажется, что они фактически приводят к NULL и не приводят к тому, что мой оператор нескольких частей становится ложным.

Я думал, что одним из решений является использование NaN или -INF или + INF, поскольку они недействительны в целевом. Но я не могу найти способ выразить это в SQL.

Есть идеи, как это решить?

EDIT:

Следующая логика решает проблему, но она многословна и не будет выполнять быстрые оценки:

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

Ответ 1

Ты можешь использовать

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

Смотрите эту статью для получения дополнительной информации по этому вопросу.

Ответ 2

Вы можете изменить ON-часть оператора слияния, поставив чек, когда оба источника и target равны нулю.

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 -- ...

Ответ 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 ....

Ответ 4

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

Ответ 6

Это также работает и может быть лучше, если у вас есть несколько столбцов, которые вы хотите проверить, отличаются ли они.

  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;

Ответ 7

Вместо того, чтобы использовать 0, когда значения равны нулю, почему бы не использовать значение, которое вряд ли существует? EG (IsNull (tgt.C, 2093128301).

Типы данных int, поэтому вам нужно много играть с......

Ответ 8

Вы можете проверить на ноль в предложении 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();

Ответ 9

WHEN MATCHED AND
(
   NULLIF(tgt.C, src.C) IS NOT NULL OR NULLIF(src.C, tgt.C) IS NOT NULL
)
THEN