Нули и оператор MERGE: мне нужно установить значение в бесконечность.Как? - PullRequest
14 голосов
/ 22 декабря 2010

В 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 равно нулю и src.C = 0, обновление не будет выполнено.Независимо от того, какое значение замещения я выберу, у меня возникнет эта проблема.

Я также пробовал синтаксис "И НЕ (... истина ...)", поскольку BOL утверждает, что вычисления с нулевым результатом приводят к FALSE.Тем не менее, кажется, что они действительно приводят к NULL и не приводят к тому, что мой оператор из нескольких частей становится ложным.

Я думал, что одним из решений является использование NaN или -INF или + INF, поскольку они недопустимы в target.Но я не могу найти способ выразить это в 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';

Ответы [ 9 ]

20 голосов
/ 21 января 2012

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

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

Подробнее об этой проблеме см. в этой статье .

13 голосов
/ 12 июля 2012

Вы можете изменить часть 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 -- ...
3 голосов
/ 23 декабря 2010

На самом деле, это работает лучше.Просто добавьте другое значение замещения как ИЛИ: -

WHEN MATCHED AND 
    ( 
    NOT (IsNull(tgt.C, 0) = IsNull(src.C, 0)) OR NOT (IsNull(tgt.C, 1) = IsNull(src.C, 1)) 
    ) 
THEN ....
2 голосов
/ 21 января 2012

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

  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;
2 голосов
/ 22 декабря 2010

Вы пробовали SET ANSI_NULLS OFF, что заставит NULL=NULL вернуть true? Это может создать дополнительные проблемы , но это может быть обходной путь на уровне сценария (выключите его, а затем включите после запуска процедуры).

2 голосов
/ 22 декабря 2010
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
0 голосов
/ 18 апреля 2019

Вы можете проверить нулевое значение в предложении 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();
0 голосов
/ 28 июня 2014
WHEN MATCHED AND
(
   NULLIF(tgt.C, src.C) IS NOT NULL OR NULLIF(src.C, tgt.C) IS NOT NULL
)
THEN
0 голосов
/ 22 декабря 2010

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

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

...