Подзапросы IN, ANY и ALL
Подзапросы для проверки принадлежности множеству и знаменитая ловушка NOT IN с NULL.
«Подзапросы IN, ANY и ALL» — бесплатный урок SQL Interview Prep на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения SQL Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс SQL Interview Prep содержит 4 уроков всего.
Подзапросы для проверки принадлежности множеству
Когда подзапрос возвращает список значений, принадлежность ему проверяют с помощью IN, ANY или ALL. Так SQL спрашивает: принадлежит ли это значение данному множеству? или больше ли оно любого / каждого элемента этого множества?
IN— совпадает с любым значением из списка.ANY/SOME— истина, если сравнение выполняется хотя бы для одного элемента.ALL— истина, только если условие выполняется для каждого элемента.
IN с подзапросом
Типичный случай: найти сотрудников, работающих в любом отделе, расположенном в городе «NYC». Подзапрос возвращает множество идентификаторов отделов, а IN оставляет строки, совпадающие хотя бы с одним из них.
Такой запрос читается естественно, и именно такую форму интервьюеры обычно ожидают увидеть первой.
SELECT name
FROM employees
WHERE dept_id IN (
SELECT id FROM departments WHERE city = 'NYC'
);= ANY — это то же самое, что IN
Полезная эквивалентность, которую любят проверять на собеседованиях: = ANY (subquery) означает ровно то же самое, что IN (subquery). В обоих случаях результат истинен, когда значение равно хотя бы одному элементу множества.
Приведённый ниже запрос возвращает тот же результат, что и предыдущий. ANY и его синоним SOME обобщают этот принцип на другие операторы, например > и <.
SELECT name
FROM employees
WHERE dept_id = ANY (
SELECT id FROM departments WHERE city = 'NYC'
);ANY с оператором сравнения
ANY становится особенно полезным с операторами > или <. Условие salary > ANY (set) истинно, если зарплата превышает хотя бы наименьший элемент — то есть больше минимального значения.
Так можно найти сотрудников, которые зарабатывают больше хотя бы одного человека из отдела 5.
SELECT name, salary
FROM employees
WHERE salary > ANY (
SELECT salary FROM employees WHERE dept_id = 5
);ALL с оператором сравнения
salary > ALL (set) истинно, только если зарплата превышает каждый элемент — то есть больше максимального значения. Так можно найти сотрудников, зарабатывающих больше всех в отделе 5.
Запомните сокращённое правило: > ALL = больше MAX, > ANY = больше MIN. Интервьюеры постоянно проверяют это знание.
SELECT name, salary
FROM employees
WHERE salary > ALL (
SELECT salary FROM employees WHERE dept_id = 5
);NOT IN: знаменитая ловушка с NULL
Перед Вами самая частая каверза на собеседованиях по подзапросам. Если подзапрос в NOT IN возвращает хотя бы один NULL, весь NOT IN может вернуть ни одной строки — а не те строки без соответствий, которые Вы ожидали.
Почему? x NOT IN (1, 2, NULL) раскрывается в x <> 1 AND x <> 2 AND x <> NULL. Последнее сравнение даёт значение UNKNOWN, поэтому условие AND никогда не может быть истинным.
SELECT name
FROM customers
WHERE id NOT IN (
SELECT customer_id FROM orders
);Почему этот запрос незаметно даёт сбой
Если orders.customer_id допускает NULL и хотя бы одна строка содержит там NULL, предыдущий запрос вернёт ноль строк, даже если клиенты без заказов явно существуют.
- Наличие NULL превращает результат логики в
UNKNOWN. - Ошибка не возникает — запрос просто возвращает неправильный, пустой результат.
Если Вы вслух упомянете эту опасность на собеседовании, это будет сильным преимуществом.
Как исправить NOT IN при наличии NULL
Интервьюеры принимают три безопасных решения:
- Исключить NULL в подзапросе: добавить
WHERE customer_id IS NOT NULL. - Переписать запрос с использованием
NOT EXISTS, который корректно обрабатывает NULL. - Использовать антисоединение
LEFT JOIN ... IS NULL.
Защищённая версия ниже возвращает настоящий список клиентов без заказов.
SELECT name
FROM customers
WHERE id NOT IN (
SELECT customer_id FROM orders
WHERE customer_id IS NOT NULL
);IN корректно работает с NULL
Утешительный факт: обычный IN без отрицания не ломается из-за NULL в списке. Условие x IN (1, 2, NULL) истинно, если x равно 1 или 2; NULL просто никогда не даёт совпадения.
Опасность NULL характерна именно для NOT IN. Умение различать эти два случая как раз отличает уверенный ответ от догадки.
Многостолбцовый IN
Некоторые диалекты (Postgres, MySQL) позволяют применять IN к кортежу столбцов, сопоставляя пары одновременно. Так можно найти строки заказов, чья комбинация (товар, регион) встречается в таблице акций.
В SQL Server отсутствует IN для значений строк; там запрос пришлось бы переписать с использованием EXISTS. Упоминание этого ограничения переносимости производит на интервьюеров хорошее впечатление.
SELECT *
FROM order_lines
WHERE (product_id, region) IN (
SELECT product_id, region FROM promotions
);Короткий ответ для собеседования
Скажите так: «IN проверяет принадлежность множеству и эквивалентен = ANY. С операторами сравнения > ANY означает “больше минимального”, а > ALL — “больше максимального”. Главная ловушка — NOT IN с подзапросом, который может вернуть NULL: запрос незаметно не возвращает ни одной строки, поэтому я добавляю IS NOT NULL или заменяю его на NOT EXISTS».
Такой ответ сразу охватывает принадлежность множеству, семантику ANY/ALL и ловушку с NULL.
Быстрая проверка
Любимая ловушка интервьюеров при обсуждении подзапросов.
Итоги
Подзапросы для проверки принадлежности множеству — закрепим:
IN== ANY: совпадает с любым элементом множества.> ANYозначает «больше минимального значения»;> ALL— «больше максимального значения».NOT INс NULL в подзапросе незаметно возвращает ни одной строки — добавляйтеIS NOT NULLили используйтеNOT EXISTS.- Обычный
INдопускает NULL; многостолбцовыйINработает в некоторых диалектах.
Далее: EXISTS и IN, а также вопрос производительности, который любят задавать на собеседованиях для опытных специалистов.
Часто задаваемые вопросы
Урок «Подзапросы IN, ANY и ALL» бесплатный?
Да — полный текст урока «Подзапросы IN, ANY и ALL» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс SQL Interview Prep, подпишись на CoddyKit PRO. Курс SQL Interview Prep содержит 4 уроков всего.
Чему я научусь в уроке «Подзапросы IN, ANY и ALL»?
Подзапросы для проверки принадлежности множеству и знаменитая ловушка NOT IN с NULL. Ты практикуешь SQL Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать SQL Interview Prep?
Предыдущий опыт не требуется. SQL Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Подзапросы IN, ANY и ALL»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке SQL Interview Prep?
Да. Каждый урок SQL Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Скалярные подзапросы в SELECT и WHERE
- Подзапросы в разделе FROM (производные таблицы)
- Подзапросы IN, ANY и ALL
- Производительность EXISTS и IN