2009-12-02 2 views
10

Итак, я спросил question этим утром, что я не правильно сформулировал, поэтому у меня появилось много ответов о том, почему NULL по сравнению с чем-либо даст NULL/FALSE.Проверка неравенства с столбцами, которые могут быть нулевыми

Мой фактический вопрос состоял в том, какова долгожданная мода, в которой парни db проверяют неравенства для двух столбцов, которые могут быть как NULL. Мой вопрос - полная противоположность этому question.

Требования следующим образом, А и В являются две колонки:
а) если А и В оба NULL, то они равны, возвращают FALSE
б) если А и В оба не равен NULL, то возвращение <> B
) если а или B являются NULL, они не равны, возвращающие

ответ

8

в зависимости от типа данных и возможных значений для столбцов:

COALESCE(A, -1) <> COALESCE(B, -1) 

хитрость состоит в поиске значение (здесь я использовал -1) -й по желанию NEVER впишите свои данные.

Другой путь будет:

(A <> B) OR (A IS NOT NULL AND B IS NULL) OR (A IS NULL AND B IS NOT NULL) 

Это может быть проблемой, в зависимости от того, как ваша конкретная СУБД обрабатывает NULLs. По стандарту ANSI это должно дать вам то, что вы хотите, но кто-либо придерживается стандартов.)

P.S. - Следует также отметить, что использование функции COALESCE может привести к недействительности использования индексов при сравнении столбцов. Проверьте свой план запроса и производительность запроса, чтобы узнать, не является ли это проблемой.

P.P.S. - Я только заметил, что OMG Ponies упомянул, что Informix не поддерживает COALESCE. Я полагаю, что это стандартная функция ANSI, но посмотрите, что я сказал выше о стандартах ...

+0

@Tom: Не то, чтобы он не поддерживал его, просто потому, что он зависит от версии/издания. –

+0

И упаковка столбца в любую функцию означает не использование индекса, если он присутствует. –

+0

Запрос coalesce не работает, если -1 является допустимым значением для столбца. Если я его код как это, и сегодня -1 не является допустимым значением, а затем оно становится допустимым значением, это будет ошибка, когда нулевое поле равно полю -1. – rouble

0

Если вы хотите быть уверенными в том, как обрабатываются NULL, вам нужно будет использовать все, что поддерживает Informix для нулевой проверки. Я много не появлялся, кроме версии SE, не поддерживающей COALESCE, но поддерживает DECODE и, возможно, CASE.

WHERE COALESCE(t.a, 0) != COALESCE(t.b, 0) 
WHERE DECODE(NULL, 0, t.a) != DECODE(NULL, 0, t.b) 
+0

Коалесцирование до 0, вероятно, плохое, поскольку было бы равно false. –

+0

@jleedev: Требование состоит в том, что 'a' и' b' не должны равняться друг другу. –

+0

Если один '0', а другой -' NULL', то вы получаете '0! = 0', что неверно, где оно должно быть истинным. –

3

Я лично напишу выражение, с которым вы столкнулись, особенно если таблица будет расти. Обтекание столбцов в вызовах функций ухудшает производительность, поэтому он не может использовать индексы, которые у вас есть в этих столбцах. Конечно, в маленькой таблице это может быть не какая-то проблема, но мне все же нравится делать это явным образом на всякий случай, когда стол заканчивается.

0

Для SQL Server, используйте:

WHERE ISNULL(A, '') <> ISNULL(B, '') 
+1

Это не работает, если '' является допустимым значением для столбца. – rouble

+1

DB is informix –

1

вы можете попробовать что-то подобное в Informix?

CASE 
    WHEN a IS NULL AND B IS NULL THEN false 
    WHEN a IS NULL OR B IS NULL THEN true 
    ELSE a <> B 
END 

от IBM Informix Guide to SQL: Syntax , CASE Expressions

+0

Я не знаю, будет ли это работать в предложении WHERE –

+0

Да, CASE-WHEN, COALESCE и NULLIF - все ANSI SQL92 и работают в WHERE. – bobince

0

Проблема в том, что a<>b (или a=b) дает NULL, а не 1 или 0, когда один или оба операнда имеют значение NULL.Это не имеет значения для случая =, поскольку NULL OR 1 - 1 и NULL OR 0 - NULL, который ведет себя как 0 для выбора в предложении WHERE.

Вы могли бы сказать:

a<>b OR (a IS NULL)<>(b IS NULL) 

Однако необходимости делать это в любом случае может быть признаком того, что вы НЕПРАВИЛЬНЫМ NULL и должен рассмотреть вопрос об изменении схемы, чтобы использовать какой-то другой NOT NULL значение для обозначения этого сопоставимого условие ,

Например, если у вас есть таблица person с столбцом title, не используйте NULL для обозначения того, что у них нет названия; это не «недостающая» дататума, просто нет названия. Поэтому сохраните его как пустую строку '', которую вы можете с радостью сравнить с другими пустыми строками. (Хорошо, если вы не запускаете Oracle, конечно, с его пустой строкой ...)

+0

Собственно, мой запрос не работает. Если только один из A или B равен NULL, мой запрос вернет FALSE, что неверно. – rouble

+0

Ah ... на самом деле не 0 (false), он возвращает NULL из-за сравнения ... но тогда в случае равенства это не имеет значения и в неравных ситуациях это делает. Редактирование ... – bobince

+0

@bobince ваше решение очень элегантно и правильно, однако оно дает синтаксическую ошибку в informix 11.5 – rouble

0

IBM Informix Dynamic Server имеет несколько своеобразное представление о булерах для множества исторических (так называемых «плохих») причин. Адаптируя идею, предложенную @astander, это выражение CASE «работает», но я бы первым сказал «не очевидно» (см. - я сказал это раньше вас!). Этап установки:

create table x(a int, b int); 
insert into x values(null, null); 
insert into x values(null, 1); 
insert into x values(1, null); 
insert into x values(1, 1); 
insert into x values(1, 2); 

ЗЕЬЕСТ:

SELECT * 
    FROM x 
    WHERE CASE 
      WHEN a IS NULL AND b IS NULL THEN 'f'::BOOLEAN 
      WHEN a IS NULL OR b IS NULL THEN 't'::BOOLEAN 
      WHEN a != b     THEN 't'::BOOLEAN 
      ELSE        'f'::BOOLEAN 
      END 
; 

результатом этого запроса:

    1 
     1   
     1   2 

Вопросы:

  • IDS не распознает FALSE или TRUE или UNKNOWN в качестве ключевых слов.
  • IDS не распознает булевские выражения, такие как 'a! = B' (или 'a <> b') как таковые.

Да, мне очень больно говорить об этом.

0

Если

where ((A=B) OR (A IS NULL AND B IS NULL)) 

это равенство, то почему бы просто не использовать:

where NOT (
    ((A=B) OR (A IS NULL AND B IS NULL)) 
) 

для неравенства?