Вы выбираете пользователей, у которых есть хотя бы один платёж. В таблице payments поле user_id иногда бывает NULL (например, анонимные платежи). Почему в такой ситуации часто предпочитают EXISTS, а не IN?
A
IN и EXISTS всегда полностью эквивалентны при любых данных, поэтому выбор между ними не влияет на корректность результатаBЛучше
IN, потому что он автоматически отбрасывает NULL в подзапросе и поэтому не зависит от пропусков в данныхCЛучше
IN, потому что он возвращает TRUE, если в подзапросе есть хотя бы один NULL среди значений сравниваемого столбцаDЧасто выбирают
EXISTS, потому что он проверяет факт существования строк и не зависит от NULL в значениях подзапросаПравильный ответ.
EXISTS отвечает на вопрос «есть ли подходящая строка», а IN сравнивает значения и может дать UNKNOWN, если список содержит NULL.Разбор
Предикат x IN (subquery) использует трёхзначную логику: если прямого совпадения нет, но в наборе есть NULL, результат может стать UNKNOWN, и строка не пройдёт фильтр. EXISTS не сравнивает значения и потому не «ломается» из-за NULL: он просто проверяет, есть ли хотя бы одна строка, удовлетворяющая условиям корреляции. Утверждения про полную эквивалентность, автоматический отброс NULL или возврат TRUE от NULL неверно описывают семантику IN.
Можно заниматься бесплатно
Готовим вопросы…
Три вопроса по теме этой страницы, с объяснениями.
Ещё вопросы по теме «Подзапросы и CTE»
- В отчёте нужно посчитать выручку по странам пользователей только по оплаченным заказам за период, причём шаг «оплаченные за период» используется ещё в трёх соседних метриках. Какой подход обычно делает запрос проверяемее и позволяет переиспользовать фильтрацию?
- Вы пишете `SELECT u.user_id, (SELECT order_id FROM orders o WHERE o.user_id = u.user_id) AS last_order_id FROM users u`. Что может пойти не так и как исправить, чтобы подзапрос стал скалярным?
- Нужно выбрать заказы, у которых `amount` выше среднего `amount` по тому же пользователю. Какой вариант `WHERE` корректно использует коррелированный подзапрос?
- Дашборд содержит две метрики на одних и тех же продажах: топ товаров по выручке за период и общая выручка за тот же период. Витрина обновляется ежедневно, и важно, чтобы фильтр по периоду был один и тот же для обеих цифр. Какой подход надёжнее защищает от рассинхронизации?
- Вы ищете пользователей без заказов запросом `SELECT u.user_id FROM users u WHERE u.user_id NOT IN (SELECT o.user_id FROM orders o)`. Почему он может вернуть 0 строк и какой подход безопаснее?
- Все вопросы по «Подзапросы и CTE» →