Основы SQL-запросов: вопросы для собеседования (часть 8)
SELECT, FROM, WHERE, ORDER BY, LIMIT — базовый синтаксис SQL, с которого начинается любое собеседование. Кажется простым, но интервьюеры проверяют порядок выполнения клауз, приоритет операторов и понимание DISTINCT. Твёрдое знание основ — фундамент, без которого сложные задачи не решить.
Вопросы 36–40 из 40
36В таблице пользователей поле `last_login` может быть `NULL` (пользователь ни разу не заходил). Нужно отсортировать пользователей так, чтобы самые недавно заходившие были сверху, а пропущенные значения оказались внизу. Какая сортировка решает обе задачи?
A`ORDER BY last_login DESC`
B`ORDER BY last_login DESC NULLS FIRST`
C`ORDER BY last_login ASC NULLS LAST`
D`ORDER BY last_login DESC NULLS LAST`
Ответ: Явно указывайте положение пропусков в сортировке через `NULLS FIRST` или `NULLS LAST`, чтобы не зависеть от дефолтов СУБД.
Нужно одновременно два требования: порядок по свежести (`DESC`) и размещение пропусков внизу (`NULLS LAST`). Поэтому корректно `ORDER BY last_login DESC NULLS LAST`. Если положение пропусков не указать явно, поведение зависит от СУБД и её настроек: где-то по умолчанию `NULL` идут в конец, где-то в начало. Для отчётов и витрин лучше задавать порядок явно, чтобы результат был предсказуемым.
Подробный разбор → 37В таблице `events` поле `created_at` имеет тип `timestamp`. Чем отличается фильтр `WHERE created_at >= '2025-03-01'` от `WHERE created_at > '2025-03-01'`?
AОба условия вернут одинаковый результат, потому что строковая дата автоматически приводится к полуночи и сравнения совпадают.
BУсловие `>=` включит события ровно в полночь первого марта, а условие `>` события ровно в полночь пропустит из выборки.
CУсловие `>` включит события ровно в полночь первого марта, а условие `>=` события ровно в полночь пропустит из выборки.
DОба условия вызовут ошибку, так как нельзя сравнивать поле типа `timestamp` со строковым литералом без явного приведения.
Ответ: При сравнении `timestamp` с датой строка `'2025-03-01'` интерпретируется как `'2025-03-01 00:00:00'` — полночь.
Строка `'2025-03-01'` при сравнении с `timestamp` интерпретируется как `'2025-03-01 00:00:00'`. Оператор `>=` включает события, произошедшие ровно в полночь, а `>` их пропускает. На практике разница обычно невелика, но если система записывает события с точностью до секунды и часть из них попадает ровно на полночь, `>=` захватит их, а `>` — нет. Ошибки сравнения здесь не возникает: приведение строки к `timestamp` выполняется неявно.
Подробный разбор → 38Какой набор строк вернёт условие `WHERE is_active = true AND NOT (country = 'RU' AND age > 25)`?
AАктивных пользователей из России старше 25 лет, у которых есть подписка на сервис компании
BВсех пользователей из России независимо от статуса активности и независимо от их возраста
CАктивных пользователей не из России или активных пользователей из России в возрасте 25 лет и младше
DНеактивных пользователей из России, а также всех пользователей младше 25 лет из любой страны
Ответ: `NOT` инвертирует выражение в скобках: `NOT (A AND B)` эквивалентно `NOT A OR NOT B` по закону де Моргана.
Условие разбирается так: `is_active = true` — берём только активных. Далее `NOT (country = 'RU' AND age > 25)` по закону де Моргана превращается в `country <> 'RU' OR age <= 25`. Итого: активные пользователи, которые либо не из России, либо из России, но возрастом 25 лет и младше. Активный пользователь из России в возрасте 30 лет под условие не попадёт.
Подробный разбор → 39Что вернёт запрос: `SELECT * FROM orders WHERE CASE WHEN status = 'shipped' THEN created_at > NOW() - INTERVAL '30 days' ELSE amount > 1000 END`?
AЗаказы со статусом `'shipped'` за последние 30 дней независимо от суммы: только ветка `THEN`, без работы ветки `ELSE`
BЗаказы с суммой больше 1000 независимо от статуса: только ветка `ELSE`, без действия условия по дате для `'shipped'`
CЗапрос вернёт ошибку: `CASE WHEN` синтаксически недопустим внутри `WHERE` и не возвращает булево выражение
DЗаказы: отправленные за последние 30 дней по ветке `THEN` или остальные с суммой больше 1000 по ветке `ELSE`
Ответ: `CASE WHEN` в `WHERE` позволяет применять разные условия фильтрации в зависимости от значений строки.
Для каждой строки `CASE` проверяет статус: если `'shipped'`, применяется условие по дате (последние 30 дней); для остальных статусов — условие по сумме (больше 1000). Это паттерн условной фильтрации: разные строки проходят через разные правила. Такой подход встречается в аналитических запросах, когда логика фильтрации зависит от категории данных.
Подробный разбор → 40Что вернёт запрос `SELECT e.name AS employee, m.name AS manager FROM employees e JOIN employees m ON e.manager_id = m.id`?
AПары «сотрудник, его руководитель»: псевдонимы `e` и `m` обращаются к одной таблице как к двум источникам через `e.manager_id = m.id`
BОшибка синтаксиса: `FROM employees e JOIN employees m` без `WITH` запрещает обращение к одной таблице дважды в одном запросе
CКаждый сотрудник дублируется: одна и та же строка попадает и в `e.name`, и в `m.name` без учёта значения `manager_id`
DТолько сотрудники с подчинёнными в той же таблице: имя руководителя в столбец `manager` по запросу не подставляется
Ответ: Псевдонимы `e` и `m` позволяют обращаться к одной таблице `employees` как к двум разным источникам в одном запросе.
Здесь таблица `employees` используется дважды: под псевдонимом `e` — как источник сотрудников, под псевдонимом `m` — как источник руководителей. Условие `e.manager_id = m.id` связывает каждого сотрудника с его руководителем. В результате получим пары «сотрудник — руководитель». Сотрудники без руководителя (`manager_id IS NULL`) не попадут в результат при обычном `JOIN` — для их включения нужен `LEFT JOIN`.
Подробный разбор →