2016-01-20 6 views
3

Выполнение сравнения пар столбцов, пытаясь найти те, которые не соответствуютSQL сравнения столбец сервера, включая Null/Не Null

SELECT 
    RecID, 
    Field1, 
    Field2 
FROM 
    TestTable 
WHERE 
    Field1 != Field2 

Однако я хочу, чтобы включить NULLS в моем чеке. Null в обоих столбцах справедливо, однако Null в одном столбце, а не в другой недопустим, так должно быть включено в выходной

SELECT 
    RecID, 
    Field1, 
    Field2 
FROM 
    TestTable 
WHERE 
    (Field1 != Field2) 
    OR (Field1 IS NULL AND Field2 IS NOT NULL) 
    OR (Field1 IS NOT NULL AND Field2 IS NULL) 

Является ли это лучший способ, чтобы написать это, или есть опрятнее/лучше способ сделать Null/Not Null сравнение?

+0

Это выглядит хорошо для меня, в чем проблема этого? – JonH

+0

@JonH Может быть, не будет никаких проблем с этим. Я знал, что так работает, но хотел знать, есть ли «правильный» способ сделать это. Если у меня есть проблема с тем, что я делаю это так, просто мой пример выше довольно упрощен - мой фактический сравнительный запрос намного больше (гораздо больше столбцов), поэтому, если есть лучший/более быстрый/более короткий способ сравнения возможно, это упростило мой запрос. – Midavalo

+2

Это правильный путь. – JonH

ответ

2

Я думал, что вы можете записать условие фильтра в немного более сжатом виде:

SELECT 
    ID, 
    Field1, 
    Field2 
FROM 
    TestTable 
WHERE 
    NOT((Field1 = Field2) OR (Field1 IS NULL AND Field2 IS NULL)) 
; 

Но этот запрос будет производить неправильный результат. Ваш вариант верен.


Connect item о предлагаемых IS DISTINCT FROM операторе упоминается @Heinzi и this answer есть ссылка на очень хороший пост Пола Уайт: Undocumented Query Plans: Equality Comparisons.

В этом сообщении Пол объясняет, что в процессоре запросов уже есть этот оператор, который используется для запросов INTERSECT.

Ваш пример можно переписать следующим образом:

SELECT 
    ID, 
    Field1, 
    Field2 
FROM 
    TestTable AS T 
WHERE 
    NOT EXISTS 
    (
     SELECT T.Field1 

     INTERSECT 

     SELECT T.Field2 
    ) 
; 
  • Он производит правильные результаты
  • Это хороший план выполнения
  • В таком виде она легко добавить несколько полей для сравнения
+0

Я пробовал то же, что и вы (инвертируя условие в записи Connect), но, как вы поняли, это не сработает. Причина этого заключается в том, что [tertium non datur] (https://en.wikipedia.org/wiki/Law_of_excluded_middle) не применяется в [тройной логике SQL] (https://en.wikipedia.org/wiki/Three- valued_logiC# Логика): И «WHERE NULL = NULL», и «WHERE NULL! = NULL» дают NULL и, следовательно, нет записей. – Heinzi

+0

Использование 'WHERE NOT EXISTS (SELECT Field1 INTERSECT SELECT Field2)' дает мне тот же результат, что и 'WHERE (Field1!= Field2) ИЛИ (поле 1 IS NULL AND Field2 IS NOT NULL) ИЛИ (Field1 IS NOT NULL AND Field2 IS NULL) ', но гораздо короче, более аккуратно и легко читается. Спасибо @ Владимир – Midavalo

1

В будущих версиях SQL Server, будет, надеюсь, будет оператор IS DISTINCT FROM. Go ahead and vote for it, if you like.

До тех пор, ваш единственный вариант - это обойти его, как вы уже это сделали. Есть и другие способы написать его - еще common variant - (a <> b OR a IS NULL OR b IS NULL) AND NOT (a IS NULL AND b IS NULL) - но я считаю решение, которое вам уже нужно читать.

+1

Элемент соединения и ответ, на который вы ссылаетесь, имеют ссылку на сообщение Пола Уайта, как 'IS DISTINCT FROM' может быть достигнуто с помощью трюка с' INTERSECT'. –

Смежные вопросы