Вы выбираете пользователей, у которых есть хотя бы один платёж. В таблице 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.
Проверь себя · 1/3разбор после ответа
Вы считаете метрику: доля пользователей, которые совершили покупку в течение 7 дней после регистрации. Какой вариант построения запроса делает логику наиболее проверяемой и удобной для отладки?
Ещё вопросы по теме «Подзапросы и 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» →