тестирование неравенства со столбцами, которые могут быть нулевыми - PullRequest
12 голосов
/ 02 декабря 2009

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

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

Требования заключаются в следующем, A и B - это два столбца:
a) если A и B равны NULL, они равны, возвращают FALSE
б) если A и B не равны NULL, вернуть A <> B
c) если A или B имеют значение NULL, они не равны, вернуть TRUE

Ответы [ 8 ]

9 голосов
/ 02 декабря 2009

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

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

Хитрость в том, чтобы найти значение (здесь я использовал -1), которое НИКОГДА не появится в ваших данных.

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

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

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

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

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

3 голосов
/ 02 декабря 2009

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

1 голос
/ 02 декабря 2009

Можете ли вы попробовать что-то подобное в 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 Руководство по SQL: синтаксис, выражения CASE

0 голосов
/ 04 февраля 2016

Если

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

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

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

за неравенство?

0 голосов
/ 03 декабря 2009

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:

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 голосов
/ 03 декабря 2009

Проблема в том, что 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 голосов
/ 02 декабря 2009

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

WHERE ISNULL(A, '') <> ISNULL(B, '')
0 голосов
/ 02 декабря 2009

Если вы хотите быть уверенным в том, как обрабатываются значения 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)
...