IN, NOT IN

Вхождение в набор данных. IN

Условие IN позволяет ответить на следующий вопрос: "Входит ( IN ) ли значение в заданный набор данных?".

Следующий пример вернет все блюда, рейтинг которых равен 320 либо 270:

select d.*
from dishes d
where d.rating IN (320, 270)

Использовать можно любые типы, не только числа:

select d.*
from dishes d
where d.name IN 
    ('Макароны с сыром', 'Овощной салат', 'Борщ')

Следуеть помнить, что при сравнении строк учитывается регистр, т.е. cледующий запрос:

select d.*
from dishes d
where d.name IN
    ('Макароны с сыром', 'ОВОЩНОЙ салат', 'БОРЩ')

Не вернет строки с овощным салатом и борщом:

Можно попробовать поправить ситуацию и воспользоваться уже знакомой функцией UPPER. Напомним, что эта функция приводит строку к верхнему регистру:

select d.*
from dishes d
where UPPER(d.name) IN
    ('Макароны с сыром', 'ОВОЩНОЙ салат', 'БОРЩ')

Итак, следующим запросом мы фактически сказали БД: "Покажи нам все строки из таблицы dishes, в которых наименование, написанное большими буквами, будет равно либо "Макароны с сыром", либо "ОВОЩНОЙ салат", либо "БОРЩ".

Почему в выборку не попали макароны с сыром и овощной салат? Ответ прост - строка "МАКАРОНЫ С СЫРОМ" не идентична строке "Макароны с сыром", как и строка "ОВОЩНОЙ САЛАТ" не идентична строке "ОВОЩНОЙ салат".

Как же можно получить все три интересующих нас блюда, не переживая за то, что регистры строк(а здесь достаточно несовпадения и хотя бы в одном символе) в таблице dishes не совпадут с регистрами строк, которые мы перечисляем в выражении IN?

Ответ прост - привести к верхнему/нижнему регистру как строки в таблице, так и строки в выражении IN.

Следующий запрос выдаст список всех интересующих нас блюд:

select d.*
from dishes d
where UPPER(d.name) IN (
    upper('Макароны с сыром'),
    upper('ОВОЩНОЙ салат'),
    upper('БОРЩ')
)

Отсутствие в наборе данных. NOT IN

Условие NOT IN выполняет функцию, противоположную выражению IN: убедиться, что значение не входит в указанный набор данных.

Напимер, нам требуется получить список блюд, за исключением чая с молоком и овощного салата:

select *
from dishes
where name not in ('Овощной салат', 'Чай с молоком')

Получим следующий результат:

Для понимания того, как работает конструкция NOT IN, лучше рассматривать приведенный пример как следующий, эквивалентный запрос:

select *
from dishes
where name <> 'Овощной салат'
and name <> 'Чай с молоком'

При использовании NOT IN, проверяемое значение будет поочередно сравнено с каждым из значений, перечисленных в скобках после NOT IN, и если хотя бы одно сравнение не будет истинным, то все условие будет считаться ложным.

Если в списке значений NOT IN будет присутствовать хотя бы одно NULL-значение, то условие будет ложным для всех обрабатываемых строк, даже тех, где проверяемое значение является NULL.

Для большего понимания рассмотрим это на примере.

Предположим, мы хотим получить список блюд, рейтинг которых не 320 и не NULL. Для этого мы написали следующий запрос:

select *
from dishes
where rating not in (320, null)

Результат получился немного не таким, как хотелось бы. Для того, чтобы понять, почему не было получено никаких данных, следует понимать, как рассматривается данный запрос:

select *
from dishes
where rating <> 320
and rating <> null

Теперь все должно быть более понятным. Причина кроется в выражении rating <> null. Как уже было рассмотрено, сравнение с NULL всегда дает ложный результат, а так как используется логическое И(and), то и результат всего выражения WHERE будет ложным.

Поэтому, используя NOT IN, всегда следует убедиться в отсутствии null-значений.

Комментарии