SQL: Пользователи без заказов
Условие
Даны таблицы users и orders.
Найдите всех пользователей, которые не сделали ни одного заказа.
Покажите несколько способов решения (LEFT JOIN, NOT EXISTS, NOT IN).
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение: Найти пользователей без заказов
Способ 1: LEFT JOIN (стандартный и быстрый)
SELECT u.user_id, u.name, u.email
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.user_id IS NULL;
Логика: LEFT JOIN соединяет таблицы, пользователи без заказов имеют NULL в полях orders. Фильтруем WHERE o.user_id IS NULL.
Производительность: O(n log n), использует индекс на orders.user_id
Преимущества:
- Читаемо и интуитивно
- Хорошая производительность
- Стандарт SQL
Способ 2: NOT EXISTS (для больших таблиц)
SELECT u.user_id, u.name, u.email
FROM users u
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.user_id = u.user_id
);
Логика: Для каждого пользователя проверяем, существует ли хотя бы один заказ. NOT EXISTS вернёт true если подзапрос не вернул ни одной строки.
Преимущества:
- Очень читаемо
- Меньше ошибок с NULL
- Early exit при первом найденном заказе
- Часто лучшая производительность на PostgreSQL/Oracle
Способ 3: NOT IN (с осторожностью!)
SELECT u.user_id, u.name, u.email
FROM users u
WHERE u.user_id NOT IN (
SELECT DISTINCT o.user_id
FROM orders o
WHERE o.user_id IS NOT NULL
);
Логика: Подзапрос находит все user_id из orders, NOT IN исключает их.
ВАЖНО! Ловушка с NULL:
- Если в orders.user_id есть NULL, NOT IN вернёт пустой результат!
- Обязательно фильтруй WHERE o.user_id IS NOT NULL
Способ 4: GROUP BY с HAVING (для аналитики)
SELECT u.user_id, u.name, u.email, COUNT(o.order_id) as order_count
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
GROUP BY u.user_id, u.name, u.email
HAVING COUNT(o.order_id) = 0;
Преимущества:
- Видна статистика (даже 0 заказов)
- Расширяемо для других метрик
Сравнение подходов
| Способ | Скорость | Читаемость | Когда использовать |
|---|---|---|---|
| LEFT JOIN | Быстро | Хорошо | Стандартный выбор |
| NOT EXISTS | Очень быстро | Отлично | Большие таблицы |
| NOT IN | Медленнее | Просто | Избегать (NULL риск) |
| GROUP BY | Зависит | Хорошо | Нужна аналитика |
Рекомендация
Используй LEFT JOIN: быстро, читаемо, стандартно, легко расширяется.
Используй NOT EXISTS: если таблица orders очень большая и индексы хорошие (особенно PostgreSQL).
Избегай NOT IN: пока не убедился что нет NULL в подзапросе!