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.rating IN (320, 270)
Использовать можно любые типы, не только числа:
select d.*
from dishes d
where d.name IN
('Макароны с сыром', 'Овощной салат', 'Борщ')
select d.*
from dishes d
where d.name IN
('Макароны с сыром', 'Овощной салат', 'Борщ')
Следует помнить, что при сравнении строк учитывается регистр, т.е. cледующий запрос:
select d.*
from dishes d
where d.name IN
('Макароны с сыром', 'ОВОЩНОЙ салат', 'БОРЩ')
select d.*
from dishes d
where d.name IN
('Макароны с сыром', 'ОВОЩНОЙ салат', 'БОРЩ')
Не вернет строки с овощным салатом и борщом:
Можно попробовать поправить ситуацию и воспользоваться уже знакомой функцией UPPER
. Напомним, что эта функция приводит строку к верхнему регистру:
select d.*
from dishes d
where UPPER(d.name) IN
('Макароны с сыром', 'ОВОЩНОЙ салат', 'БОРЩ')
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('БОРЩ')
)
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 ('Овощной салат', 'Чай с молоком')
select *
from dishes
where name not in ('Овощной салат', 'Чай с молоком')
Получим следующий результат:
Для понимания того, как работает конструкция NOT IN, лучше рассматривать приведенный пример как следующий, эквивалентный запрос:
select *
from dishes
where name <> 'Овощной салат'
and name <> 'Чай с молоком'
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 not in (320, null)
Результат получился немного не таким, как хотелось бы. Чтобы понять, почему не было получено никаких данных, рассмотрим, как работает данный запрос:
select *
from dishes
where rating <> 320
and rating <> null
select *
from dishes
where rating <> 320
and rating <> null
Теперь все должно быть более понятным. Причина кроется в выражении rating <> null
. Сравнение с NULL
всегда дает ложный результат, а так как используется логическое И(and), то и результат всего выражения WHERE будет ложным.
Поэтому, используя NOT IN
, всегда следует убедиться в отсутствии null-значений.