SQL IN: фильтрация строк по списку значений

Оператор SQL IN проверяет, совпадает ли значение хотя бы с одним элементом списка. Предикат SQL WHERE IN заменяет длинные цепочки OR, когда нужно фильтровать по известному набору дискретных значений: кодам статусов, названиям категорий, идентификаторам регионов. Используйте список SQL WHERE IN, когда значения известны заранее и условие должно оставаться читаемым по мере роста.

Пример SQL IN Для Сопоставления Со Списком

Вывод:

Результат появится здесь...

Вывод:

+------------+-------------+
| name       | category    |
+------------+-------------+
| Блокнот    | канцтовары  |
| Клавиатура | электроника |
| Ластик     | канцтовары  |
| Мышь       | электроника |
+------------+-------------+
4 row(s)

Как Работает Этот Пример

  1. CREATE TABLE и INSERT заполняют таблицу products пятью строками в трех категориях.
  2. WHERE category IN ('электроника', 'канцтовары') выбирает любую строку, где category равна одному из указанных значений. Логически это эквивалентно category = 'электроника' OR category = 'канцтовары'.
  3. Строка с мебель исключается, потому что эта category не входит в список.
  4. ORDER BY name делает вывод детерминированным.

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

Что Такое Оператор SQL IN?

Оператор SQL IN - это сокращенная форма для нескольких проверок на равенство, объединенных через OR. WHERE x IN (a, b, c) логически идентичен WHERE x = a OR x = b OR x = c. В трехзначной логике SQL, если ни один элемент списка не совпал и в списке нет NULL, IN возвращает false. Если в списке есть NULL и точного совпадения нет, результат unknown; в WHERE строка с unknown отфильтровывается.

Как Обрабатывать Пустой Список SQL WHERE IN

Большинство баз данных отклоняют WHERE col IN () как синтаксическую ошибку. Обычно это появляется при динамической генерации списка SQL WHERE IN. Пустой случай нужно обрабатывать явно: пропускать фильтр или подставлять заведомо ложный предикат вроде WHERE 1 = 0, если пустой список должен вернуть ноль строк.

SQL NOT IN И Ловушка NULL

SQL NOT IN инвертирует проверку: он возвращает true только когда значение не равно каждому элементу списка. Один NULL в списке может перевести результат в unknown, потому что x <> NULL всегда unknown, а WHERE трактует unknown как false:

-- Вернет 0 строк: NULL делает предикат UNKNOWN
SELECT name
FROM products
WHERE category NOT IN ('электроника', NULL);

Если список приходит из подзапроса, отфильтруйте NULL внутри подзапроса или используйте NOT EXISTS для NULL-безопасной семантики.

IN С Подзапросами

IN также принимает подзапрос вместо литерального списка. Концептуально подзапрос формирует набор значений, а внешний запрос проверяет принадлежность:

SELECT name FROM products
WHERE category IN (
  SELECT category FROM products WHERE name LIKE '%нот%'
);

Для небольших некоррелированных подзапросов это работает хорошо. Когда подзапрос возвращает много строк или содержит корреляцию, предикат EXISTS или JOIN часто работает быстрее, потому что оптимизатор может применять стратегии semi-join.

IN vs EXISTS vs JOIN

ПодходИспользуйте, когда…
IN (list)Нужна фильтрация по небольшому известному набору литеральных значений
IN (subquery)Нужна проверка принадлежности к небольшому non-null набору
EXISTS (subquery)Нужна коррелированная проверка или nullable внешние ключи
JOINНужны столбцы из обеих таблиц в результате
BETWEENЗначения образуют непрерывный диапазон, а не дискретные элементы

Правило: используйте IN для дискретных наборов значений. Переключайтесь на EXISTS, если подзапрос коррелированный или nullable. Используйте JOIN, когда нужны данные с обеих сторон.

Заметки О Производительности

IN по индексируемому столбцу является sargable: оптимизатор может выполнить индексные поиски для каждого значения списка. Некоторые движки сортируют литеральные списки IN внутри плана для бинарного поиска. Очень большие литеральные списки (сотни значений) могут замедлить разбор запроса и построение плана; в таком случае лучше загрузить значения во временную таблицу и использовать JOIN.

FAQ

SQL IN Это То Же Самое, Что И Несколько Условий OR?

Логически да. WHERE x IN (1, 2, 3) эквивалентно WHERE x = 1 OR x = 2 OR x = 3. Оптимизатор обычно строит одинаковый план выполнения для обеих форм, но IN короче и его проще поддерживать по мере роста списка.

Почему NOT IN Не Возвращает Строки, Когда Подзапрос Содержит NULL?

NOT IN разворачивается в цепочку AND-сравнений: x <> a AND x <> b AND x <> NULL. Поскольку x <> NULL всегда unknown, все выражение никогда не становится true. Отфильтруйте NULL в подзапросе или используйте NOT EXISTS, чтобы избежать этой проблемы.

Можно Ли Использовать IN С Подзапросом?

Да. WHERE col IN (SELECT col FROM other_table) проверяет принадлежность результату подзапроса. Для небольших non-null наборов это эффективно. Для больших или nullable наборов EXISTS или JOIN часто дают оптимизатору больше гибкости.