Основы SQL-запросов: вопросы для собеседования (часть 7)

SELECT, FROM, WHERE, ORDER BY, LIMIT — базовый синтаксис SQL, с которого начинается любое собеседование. Кажется простым, но интервьюеры проверяют порядок выполнения клауз, приоритет операторов и понимание DISTINCT. Твёрдое знание основ — фундамент, без которого сложные задачи не решить.

Агрегация, GROUP BY и HAVINGДаты и времяEXPLAIN и оптимизацияВыражения и NULLJOIN и операции множествСтроки и приведение типовПодзапросы и CTEОконные функции

Вопросы 3135 из 40

31В запросе `SELECT u.name FROM users u WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id)` — как работает `EXISTS`?
AПодзапрос в `EXISTS` проверяет наличие хотя бы одной строки: при наличии условие истинно
BПодзапрос в `EXISTS` обязан вернуть единственную строку, иначе возникает ошибка выполнения
CПодзапрос в `EXISTS` возвращает список значений, который служит фильтром во внешнем запросе
DПодзапрос в `EXISTS` возвращает количество совпавших строк и сравнивает его с порогом
Ответ: `EXISTS` возвращает `TRUE`, если подзапрос возвращает хотя бы одну строку, иначе — `FALSE`.

`EXISTS` не анализирует конкретные значения из подзапроса — важен сам факт наличия строк. Для каждой строки внешней таблицы подзапрос проверяет, есть ли хотя бы одна совпадающая строка по условию связи. Если есть — строка попадает в результат. Именно поэтому в подзапросе часто пишут `SELECT 1` — возвращаемое значение не имеет значения, проверяется только наличие.

Подробный разбор →
32Что вернёт запрос `SELECT name FROM users WHERE id IN (SELECT user_id FROM orders WHERE created_at >= '2025-01-01')`?
AЗапрос вернёт ошибку: подзапрос в `IN` не может ссылаться на другую таблицу через её столбцы внутри
BЗапрос вернёт всех пользователей: фильтр `WHERE id IN (...)` не ограничивает результат списком из подзапроса
CЗапрос вернёт пользователей, чей `id` есть хотя бы в одном заказе за 2025 год по фильтру `IN`
DЗапрос вернёт пользователей, у которых все заказы сделаны только в 2025 году, через логику `IN` напрямую
Ответ: Подзапрос в `IN` возвращает набор значений, и основной запрос фильтрует строки по вхождению в этот набор.

Подзапрос `SELECT user_id FROM orders WHERE created_at >= '2025-01-01'` формирует список идентификаторов пользователей, сделавших хотя бы один заказ с начала 2025 года. Затем `WHERE id IN (...)` оставляет только тех пользователей из таблицы `users`, чей `id` входит в этот список. Это стандартный паттерн для фильтрации по связанной таблице. Условие «все заказы только в 2025 году» формулируется иначе — обычно через `NOT EXISTS` для записей вне нужного диапазона.

Подробный разбор →
33В таблице событий поле `updated_at` может быть `NULL` (ещё не обработано). Нужно отсортировать так: сначала обработанные события по свежести обновления, затем необработанные внизу, и при одинаковом `updated_at` порядок должен быть стабильным по `event_id`. Какой `ORDER BY` соответствует этому?
A`ORDER BY updated_at DESC NULLS FIRST, event_id ASC`
B`ORDER BY updated_at DESC, event_id ASC`
C`ORDER BY updated_at DESC NULLS LAST`
D`ORDER BY updated_at DESC NULLS LAST, event_id ASC`
Ответ: Сочетайте `NULLS LAST` для положения пропусков и второй столбец в `ORDER BY` для стабильности при совпадениях.

Условие «сначала свежие обновления» означает `updated_at DESC`. Условие «пропуски внизу» означает `NULLS LAST`. Условие стабильного порядка при одинаковом `updated_at` означает добавление второго ключа сортировки, например `event_id ASC`. Без второго ключа порядок строк с одинаковым `updated_at` может меняться от запроса к запросу. Поэтому корректная сортировка: `ORDER BY updated_at DESC NULLS LAST, event_id ASC`.

Подробный разбор →
34Маркетинг хочет сначала увидеть пользователей, которые ни разу не заходили (значение `last_login` пустое), а затем — остальных по возрастанию даты входа (чем раньше последний вход, тем выше). Какой `ORDER BY` соответствует этому требованию?
A`ORDER BY last_login DESC NULLS LAST`
B`ORDER BY last_login ASC NULLS LAST`
C`ORDER BY last_login DESC NULLS FIRST`
D`ORDER BY last_login ASC NULLS FIRST`
Ответ: Для подъёма пустых значений наверх используется `NULLS FIRST`, а направление `ASC` или `DESC` управляет порядком непустых дат.

Требование «сначала пустые значения» означает `NULLS FIRST`, а требование «остальные по возрастанию даты» означает `ASC`. Итоговая запись `ORDER BY last_login ASC NULLS FIRST` ставит сверху пользователей без активности, а ниже — тех, кто заходил давно, в порядке роста даты. Это удобно, когда нужно приоритизировать неактивных пользователей в списках для реактивации.

Подробный разбор →
35Вы делаете пагинацию по заказам: `SELECT order_id, created_at FROM orders ORDER BY created_at DESC LIMIT 50 OFFSET 50`. Иногда один и тот же `order_id` встречается на двух страницах. Какое улучшение проще всего сделать в рамках этих же операторов, чтобы порядок был более детерминированным?
AПоднять `LIMIT` до 100, чтобы реже перелистывать страницы и снизить шанс пересечения строк
BУбрать `OFFSET` и оставить только `LIMIT 50` без второго столбца в `ORDER BY`
CДобавить фильтр `WHERE created_at IS NOT NULL` для защиты от пропусков и повторов
DДописать второй ключ в сортировку: `ORDER BY created_at DESC, order_id DESC`
Ответ: Добавляйте уникальный tie-breaker в `ORDER BY`, если первый столбец сортировки не уникален.

Если `created_at` повторяется у многих заказов, то порядок строк с одинаковым временем может «плавать». Это особенно заметно при `LIMIT`/`OFFSET`, когда граница страницы проходит внутри группы одинаковых значений. Добавив уникальный столбец в сортировку, например `order_id`, вы фиксируете порядок: `ORDER BY created_at DESC, order_id DESC`. Это не решает всех проблем `OFFSET` при изменяющихся данных, но делает порядок воспроизводимым для одного и того же набора строк.

Подробный разбор →
12345678

Хотите тренировать интерактивно?

В приложении — таймер, прогресс, стрики и 1700+ вопросов по всем темам.

Тренировать SQL в Telegram

Другие темы: SQL

Агрегация, GROUP BY и HAVINGДаты и времяEXPLAIN и оптимизацияВыражения и NULLJOIN и операции множествСтроки и приведение типовПодзапросы и CTEОконные функции