Ответ 1
Ты можешь использовать
WHEN MATCHED AND EXISTS (SELECT tgt.C EXCEPT SELECT src.C)
Смотрите эту статью для получения дополнительной информации по этому вопросу.
В 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';
Ты можешь использовать
WHEN MATCHED AND EXISTS (SELECT tgt.C EXCEPT SELECT src.C)
Смотрите эту статью для получения дополнительной информации по этому вопросу.
Вы можете изменить 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 -- ...
Собственно, это работает лучше. Просто добавьте другое значение замены как OR: -
WHEN MATCHED AND
(
NOT (IsNull(tgt.C, 0) = IsNull(src.C, 0)) OR NOT (IsNull(tgt.C, 1) = IsNull(src.C, 1))
)
THEN ....
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
Вы пробовали SET ANSI_NULLS OFF
, который сделает NULL=NULL
return true? Это может создать дополнительные проблемы, но это может быть обходное решение script (выключите его, а затем, когда вы запустите свой процесс).
Это также работает и может быть лучше, если у вас есть несколько столбцов, которые вы хотите проверить, отличаются ли они.
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;
Вместо того, чтобы использовать 0, когда значения равны нулю, почему бы не использовать значение, которое вряд ли существует? EG (IsNull (tgt.C, 2093128301).
Типы данных int, поэтому вам нужно много играть с......
Вы можете проверить на ноль в предложении 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();
WHEN MATCHED AND
(
NULLIF(tgt.C, src.C) IS NOT NULL OR NULLIF(src.C, tgt.C) IS NOT NULL
)
THEN