Тестирование неравенства со столбцами, которые могут быть нулевыми
Автор вопроса: roubleОтветов: 9
Итак, сегодня утром я задал вопрос, что и сделал неправильно выразился, поэтому я получил много ответов о том, почему NULL по сравнению с чем-либо даст NULL/FALSE.
Мой фактический вопрос заключался в том, какова проверенная временем мода, в которой ребята из базы данных проверяют неравенства для двух столбцов, которые могут быть NULL. Мой вопрос прямо противоположен этому вопросу.
Требования следующие: A и B - два столбца: а) если A и B оба равны NULL, они равны, вернуть FALSE б) если A и B оба не NULL, вернуть A‹ >B c) если A или B равны NULL, они не равны, вернуть TRUE
В зависимости от типа данных и возможных значений столбцов:
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 может сделать недействительным использование индексов при сравнении столбцов. Проверьте свой план запроса и производительность запроса, чтобы убедиться, что это проблема.
П.П.С. - Я только что заметил, что OMG Ponies упомянули, что Informix не поддерживает COALESCE. Я считаю, что это стандартная функция ANSI, но посмотрите, что я сказал выше о стандартах...
Ответ 2 · рейтинг 3 · Donnie
Я бы лично записал выражение, которое вы придумали, особенно если ожидается, что таблица станет большой. Оборачивание столбцов в вызовы функций снижает производительность, так как движок не может использовать какие-либо индексы, которые у вас есть для этих столбцов. Конечно, в маленькой таблице это может не быть проблемой, но мне все же нравится делать это явным образом на случай, если таблица в конечном итоге будет расти.
Ответ 3 · рейтинг 1 · Adriaan Stander
Вы можете попробовать что-то подобное в 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
Ответ 4 · OMG Ponies
Если вы хотите быть уверены в том, как обрабатываются значения NULL, вам придется использовать все, что Informix поддерживает для проверки значений NULL. Я не нашел многого, за исключением того, что версия SE не поддерживает COALESCE, но поддерживает DECODE и, возможно, CASE.
WHERE COALESCE(t.a, 0) != COALESCE(t.b, 0)
WHERE DECODE(NULL, 0, t.a) != DECODE(NULL, 0, t.b)
Ответ 5 · Gordon Bell
Для SQL Server используйте:
WHERE ISNULL(A, '') <> ISNULL(B, '')
Ответ 6 · bobince
Проблема в том, что 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 с его проблемой с пустой строкой...)
Ответ 7 · Jonathan Leffler
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'), как таковые.
Да, мне очень больно говорить об этом.
Ответ 8 · user3830747
If
where ((A=B) OR (A IS NULL AND B IS NULL))
для равенства, то почему бы просто не использовать:
where NOT (
((A=B) OR (A IS NULL AND B IS NULL))
)