Предложение IN с NULL или IS NULL

85

Postgres - это база данных

Могу ли я использовать значение NULL для предложения IN? пример:

SELECT *
FROM tbl_name
WHERE id_field IN ('value1', 'value2', 'value3', NULL)

Я хочу ограничиться этими четырьмя ценностями.

Я пробовал вышеуказанный оператор, и он не работает, он выполняется, но не добавляет записи с NULL id_fields.

Я также попытался добавить условие ИЛИ, но это просто заставило запрос выполняться и выполняться без конца.

SELECT *
FROM tbl_name
WHERE other_condition = bar
AND another_condition = foo
AND id_field IN ('value1', 'value2', 'value3')
OR id_field IS NULL

Какие-либо предложения?

Фил Паффорд
источник
10
inЗаявление будет разобрано идентично field=val1 or field=val2 or field=val3. Ввод ноля там будет сводиться к тому, field=nullчто не сработает.
Marc B
1
второй запрос должен быть правильным. что еще есть в вашей whereстатье?
Daniel A. White
@ Дэниел А. Уайт, обновлено, чтобы отразить запрос с дополнительными условиями
Фил Паффорд

Ответы:

126

inЗаявление будет разобрано идентично field=val1 or field=val2 or field=val3. Ввод ноля там будет сводиться к тому, field=nullчто не сработает.

( Комментарий от Marc B )

Я бы сделал это для ясности

SELECT *
FROM tbl_name
WHERE 
(id_field IN ('value1', 'value2', 'value3') OR id_field IS NULL)
Дэниел А. Уайт
источник
Ах, вот и все, спасибо! Итак, упаковка полей добавляет оба условия в предложение WHERE? Просто для пояснения
Фил Паффорд
1
@Phill - это проблема порядка работы.
Daniel A. White
20

Ваш запрос не выполняется из-за приоритета оператора . ANDсвязывает раньше OR!
Вам понадобится пара круглых скобок, и это не вопрос «ясности», а чисто логическая необходимость .

SELECT *
FROM   tbl_name
WHERE  other_condition = bar
AND    another_condition = foo
AND   (id_field IN ('value1', 'value2', 'value3') OR id_field IS NULL)

Добавленные скобки предотвращают ANDпривязку раньше OR. Если бы не было других WHEREусловий (нет AND), скобки не понадобились бы . Принятый ответ в этом отношении немного вводит в заблуждение.

Эрвин Брандштеттер
источник
15
SELECT *
FROM tbl_name
WHERE coalesce(id_field,'unik_null_value') 
IN ('value1', 'value2', 'value3', 'unik_null_value')

Чтобы вы исключили из проверки нуль. Учитывая нулевое значение в id_field, функция coalesce вместо null вернет unik_null_value, и, добавив unik_null_value в IN-список, запрос вернет сообщения, где id_field имеет значение 1-3 или null.

Уве Халсет
источник
2
Небольшое пояснение будет полезно будущим читателям. Как ваш код помогает решить проблему?
showdev
9

Вопрос, на который ответил Даниил, действительно хорош. Я хотел оставить замечание по поводу NULLS. Мы должны быть осторожны при использовании оператора NOT IN, когда столбец содержит значения NULL. Вы не получите никакого вывода, если ваш столбец содержит значения NULL и вы используете оператор NOT IN. Вот как это объясняется здесь http://www.oraclebin.com/2013/01/beware-of-nulls.html , очень хорошая статья, на которую я наткнулся и решил поделиться ею.

Сушант Бутта
источник
Не уверен, сколько пользователей столкнулись с этой проблемой, но у меня была именно эта проблема, когда смешивались нули и оператор NOT IN, и последние два часа я боролся с ней. ЭТО преступник ...
Говинд Рай
1
Ссылка мертвая.
Dag Høidahl
1
Вроде живо сейчас.
всегда-ученик
3

Примечание: поскольку кто-то утверждал, что внешняя ссылка мертва в ответе Сушанта Бутты, я разместил этот контент здесь как отдельный ответ.

Остерегайтесь NULLS .

Сегодня я столкнулся с очень странным поведением запроса при использовании IN и NOT INоператоров. На самом деле я хотел сравнить две таблицы и выяснить , является ли значение из table bсуществовавших в table aили нет , и выяснить его поведение , если столбец содержитnull значение. Поэтому я просто создал среду для проверки этого поведения.

Создадим стол table_a.

SQL> create table table_a ( a number);
Table created.

Создадим стол table_b.

SQL> create table table_b ( b number);
Table created.

Вставьте некоторые значения в table_a.

SQL> insert into table_a values (1);
1 row created.

SQL> insert into table_a values (2);
1 row created.

SQL> insert into table_a values (3);
1 row created.

Вставьте некоторые значения в table_b.

SQL> insert into table_b values(4);
1 row created.

SQL> insert into table_b values(3);
1 row created.

Теперь мы выполним запрос, чтобы проверить наличие значения в table_a, проверив его значение с table_bпомощью INоператора using .

SQL> select * from table_a where a in (select * from table_b);
         A
----------
         3

Выполните запрос ниже, чтобы проверить его отсутствие.

SQL> select * from table_a where a not in (select * from table_b);
         A
----------
         1
         2

Результат пришел как и ожидалось. Теперь мы вставим nullзначение в таблицу table_bи посмотрим, как ведут себя два вышеуказанных запроса.

SQL> insert into table_b values(null);
1 row created.

SQL> select * from table_a where a in (select * from table_b);
         A
----------
         3

SQL> select * from table_a where a not in (select * from table_b);

no rows selected

Первый запрос вел себя так, как ожидалось, но что случилось со вторым запросом? Почему мы не получили никакого вывода, что должно было произойти? Есть ли разница в запросе? Нет .

Изменение есть в данных таблицы table_b. Мы ввели nullзначение в таблицу. Но почему он так себя ведет? Давайте разделим два запроса в "AND"и "OR"оператор.

Первый запрос:

Первый запрос будет обрабатываться внутри примерно так. Таким образом, a nullне создаст здесь проблемы, поскольку мои первые два операнда будут либо оценивать, trueлибо false. Но мой третий операнд не a = nullбудет ни оценивать trueни false. Будет оценивать nullтолько.

select * from table_a whara a = 3 or a = 4 or a = null;

a = 3  is either true or false
a = 4  is either true or false
a = null is null

Второй запрос:

Второй запрос будет обработан, как показано ниже. Поскольку мы используем "AND"оператор, и что-либо, кроме trueлюбого операнда, не даст мне никакого вывода.

select * from table_a whara a <> 3 and a <> 4 and a <> null;

a <> 3 is either true or false
a <> 4 is either true or false
a <> null is null

Так как же нам с этим справиться? Мы выберем все not nullзначения из таблицы table_bпри использовании NOT INоператора.

SQL> select * from table_a where a not in (select * from table_b where b is not null);

         A
----------
         1
         2

Поэтому всегда будьте осторожны со NULLзначениями в столбце при использовании NOT INоператора.

Остерегайтесь NULL !!

1000111
источник
Отличный ответ. Я только что обнаружил проблему в своей работе. Очень-очень странное поведение Oracle.
опутюк 01
0

Я знаю, что поздно ответить, но может быть полезно для кого-то еще. Вы можете использовать подзапрос и преобразовать нуль в 0

SELECT *
FROM (SELECT CASE WHEN id_field IS NULL 
                THEN 0 
                ELSE id_field 
            END AS id_field
      FROM tbl_name) AS tbl
WHERE tbl.id_field IN ('value1', 'value2', 'value3', 0)
ch2o
источник
Это похоже на ответ Ове Халсета с использованием coalesce.
user890332 09
0

Nullотносится к отсутствию данных. Nullформально определяется как значение, которое недоступно, не назначено, неизвестно или неприменимо (OCA Oracle Database 12c, SQL Fundamentals I Exam Guide, стр. 87). Таким образом, вы можете не видеть записи со столбцами, содержащими нулевые значения, когда указанные столбцы ограничены с помощью предложений «in» или «not in».

Роджер Роу
источник