Проверьте на!= Значения, когда столбец содержит записи с NULL
У меня есть несколько таблиц, которые смешивают "реальные" значения с нулями в столбцах. Исходя из опыта, выполняя SELECT против этих, который выглядит следующим образом:
SELECT column1, column2, column3 FROM mytable WHERE column1 != 'a value';
... не возвращает записи, которые я ожидаю. В текущей таблице, над которой я работаю, это возвращает пустой набор записей, хотя я знаю, что у меня есть записи в таблице с NULL в column1 и другие записи в таблице, которые имеют значение "!=" В column1. В этом случае я ожидаю увидеть записи со значениями NULL в столбце 1 (и, конечно же, все остальное, если в столбце 1 были значения, отличные от "значения").
Эксперименты с NVL в предложении WHERE, кажется, не дают мне ничего особенного:
SELECT column1, column2, column3 FROM mytable WHERE NVL(column1, '') != 'a value';
... также возвращает пустой набор записей.
Использование 'IS NULL' технически даст мне правильный набор записей в моем текущем примере, но, конечно, если какие-либо записи изменятся на что-то вроде 'другого значения' в столбце 1, то IS NULL исключит их.
5 ответов
NULL нельзя сравнивать так же, как и другие значения. Вы должны использовать IS NULL. Если вы хотите включить значения NULL, добавьте OR к предложению WHERE:
SELECT column1, column2, column3 FROM mytable WHERE column1 != 'a value' OR column1 IS NULL
Запрос не работает, потому что SQL обрабатывает проверки на равенство (!=), Отличные от проверки, если NULL (IS NULL).
Что вы могли бы сделать здесь что-то вроде:
SELECT column1, column2, column3
FROM mytable
WHERE column1 != 'a value' OR column1 is null;
Смотрите Не равно <>!= Оператор на NULL.
То, что вы пытались, было правильно. Вам просто нужно немного его изменить. увидеть ниже-
SELECT column1, column2, column3 FROM mytable WHERE NVL(column1, '0') != 'a value';
Вместо пустой строки передайте любой символ во втором аргументе NVL.
1) Недокументированная функция Oracle SYS_OP_MAP_NONNULL. (Существует от oracle10)
with abc as ( select 'a value' as col1 from dual
union all
select '' as col1 from dual)
select * from abc
where SYS_OP_MAP_NONNULL(col1) != SYS_OP_MAP_NONNULL('a value')
;
2) LNNVL - проверьте таблицу в документации для уточнения.
with abc as ( select 'a value' as col1 from dual
union all
select '' as col1 from dual)
select * from abc
where lnnvl( col1 = 'a value');
;
"Эксперимент с NVL в предложении WHERE, кажется, не дает мне ничего особенного"
Это правда:
SQL> select * from mytable;
COLUMN1 COLUMN2 COLUMN3
-------------------- ---------- ---------
a value 1 25-JUL-17
not a value 2 25-JUL-17
whatever 3 25-JUL-17
4 26-JUL-17
SQL> SELECT column1, column2, column3 FROM mytable WHERE NVL(column1, '') != 'a value';
COLUMN1 COLUMN2 COLUMN3
-------------------- ---------- ---------
not a value 2 25-JUL-17
whatever 3 25-JUL-17
SQL>
Это потому, что ваш эксперимент не зашел достаточно далеко. По историческим причинам Oracle рассматривает пустую строку как null
Так что ваши nvl()
утверждение фактически просто подменяет один ноль для другого. Но если бы вы использовали правильное значение в своем вызове, вы бы получили желаемый результат:
SQL> SELECT column1, column2, column3 FROM mytable WHERE NVL(column1, 'meh') != 'a value';
COLUMN1 COLUMN2 COLUMN3
-------------------- ---------- ---------
not a value 2 25-JUL-17
whatever 3 25-JUL-17
4 26-JUL-17
SQL>
Альтернативный подход заключается в явном тестировании на NULL и тестировании на исключающее значение...
SQL> SELECT column1, column2, column3 FROM mytable
2 where column1 is null or column1 != 'a value';
COLUMN1 COLUMN2 COLUMN3
-------------------- ---------- ---------
not a value 2 25-JUL-17
whatever 3 25-JUL-17
4 26-JUL-17
SQL>
Второй подход, вероятно, более ортодоксален.