2013-03-12 2 views
3

Способ, которым эти строки обычно попадают в целевую таблицу в первый раз с редким числом столбцов, заполненных в основном текстовыми данными, а остальная часть столбцов установлена ​​в NULL. При последующих проходах свежие данные заполняют существующие известные (не нулевые) и неизвестные (NULL) данные. Я убедился, что свежие данные (#pld) действительно содержат разные данные. Данные не изменяются. Вот что у меня есть:sql server: MERGE имеет неожиданные результаты

BEGIN TRANSACTION 

    BEGIN TRY 


    MERGE INTO [metro].listings AS metroList 
    USING #pld as listnew 
     ON metroList.id = listnew.id 
     AND metroList.sid = listnew.sid 
     WHEN MATCHED AND (
     metroList.User != listnew.User 
     or metroList.Email != listnew.Email 
     or metroList.LocName != listnew.LocName 
    ) THEN 
    UPDATE SET 
    metroList.User = listnew.User, 
    metroList.Email = listnew.Email, 
    metroList.LocName = listnew.LocName, 
    WHEN NOT MATCHED THEN 
    INSERT 
    (User, 
    Email, 
    LocName 
    ) 
    VALUES 
    (
    listnew.User, 
    listnew.Email, 
     listnew.LocName 
    ); 

    COMMIT TRANSACTION 

END TRY 


IF @@TRANCOUNT > 0 
    ROLLBACK TRANSACTION; 

END CATCH 

Я попытался замены = в соответствии с частью обновления заявления с <>!. Те же результаты. Это должно быть связано с сопоставлением возможного (вероятного) значения null со строкой - возможно, даже с другим значением null? Во всяком случае, я призываю всех разработчиков sql-geeks распутать это.

ответ

3

Также вы можете использовать опцию с функцией NULLIF().

NULLIF возвращает первое выражение, если два выражения не равны. Если выражения равны, NULLIF возвращает нулевое значение типа первого выражения.

WHEN MATCHED AND (
        NULLIF(ISNULL(metroList.[User],''), listnew.[User]) IS NOT NULL 
        OR NULLIF(ISNULL(metroList.Email, ''), listnew.Email) IS NOT NULL 
        OR NULLIF(ISNULL(metroList.LocName, ''), listnew.LocName) IS NOT NULL 
       ) 
THEN 
+0

Не выглядит правильно мне. –

+0

ooops.My fault.NULLIF() не работает, если первое значение равно NULL. В моем обновлении я проверяю его с помощью ISNULL(). Извините еще раз и спасибо @Martin Smith +100500 –

2

Сравнение NULL с пустой строкой не будет работать.

Если одна из сторон может быть NULL, вы могли бы сделать что-то вроде:

WHEN MATCHED AND (
     COALESCE(metroList.User, '') <> COALESCE(listnew.User, '') 
    or COALESCE(metroList.Email, '') <> COALESCE(listnew.Email, '') 
    or COALESCE(metroList.LocName, '') <> COALESCE(listnew.LocName, '') 
    ) THEN 

Конечно, это предполагает, что вы хорошо с NULL означает то же самое, как пустая строка (которая не может быть целесообразным) ,

Посмотрите на this BOL article на NULL сравнения.

2

Как я понимаю, вопрос, который вы ищете выражение, которое эмулирует IS DISTINCT FROM.

Ответ вы приняли не правильно, то

WITH metroList([User]) 
    AS (SELECT CAST(NULL AS VARCHAR(10))), 
    listnew([User]) 
    AS (SELECT 'Foo') 
SELECT * 
FROM metroList 
     JOIN listnew 
     ON NULLIF(metroList.[User], listnew.[User]) IS NOT NULL 

Возвращает ноль строк. Несмотря на сопоставимые значения: NULL и Foo.

Я хотел бы использовать технику из этой статьи: Undocumented Query Plans: Equality Comparisons

WHEN MATCHED AND EXISTS (
         SELECT metroList.[User], metroList.Email,metroList.LocName 
         EXCEPT 
         SELECT listnew.[User], listnew.Email,listnew.LocName 
         )  
+0

вариант с EXCEPT - лучший;) –