Агрегация, GROUP BY и HAVING: вопросы для собеседования (часть 2)

GROUP BY, HAVING, COUNT, SUM, AVG — агрегатные функции встречаются практически в каждой SQL-задаче на собеседовании. Интервьюеры проверяют, понимаете ли вы разницу между WHERE и HAVING, умеете ли группировать по нескольким полям и фильтровать по результатам агрегации. Без уверенного владения этим блоком невозможно решить ни одну аналитическую задачу на SQL.

Даты и времяEXPLAIN и оптимизацияВыражения и NULLJOIN и операции множествОсновы SQL-запросовСтроки и приведение типовПодзапросы и CTEОконные функции

Вопросы 610 из 32

6Нужно сгруппировать события по календарному месяцу в PostgreSQL, чтобы все дни одного месяца попали в одну группу. Какой подход правильный?
AНаписать `GROUP BY YEAR(event_time), MONTH(event_time)` — стандартный синтаксис для всех СУБД
BИспользовать `GROUP BY EXTRACT(month FROM event_time)` — извлекает номер месяца из даты
CНаписать `GROUP BY DATE_TRUNC('month', event_time)` — усекает временную метку до начала месяца
DПрименить `GROUP BY CAST(event_time AS DATE)` — обрезает время, оставляя только дату
Ответ: `DATE_TRUNC('month', ts)` усекает метку до `YYYY-MM-01 00:00:00` — все дни одного месяца принимают одно значение и попадают в одну группу.

`DATE_TRUNC(unit, timestamp)` возвращает метку времени, усечённую до указанной единицы. `DATE_TRUNC('month', ts)` превращает любую дату месяца в `YYYY-MM-01 00:00:00`. `EXTRACT(month FROM ts)` возвращает только номер месяца 1–12 и смешивает разные годы — январь 2023 и январь 2024 окажутся в одной группе. `CAST(ts AS DATE)` группирует по дням, а не месяцам.

7Как `GROUP BY` обрабатывает значения `NULL` в столбце группировки?
A`NULL` игнорируются и не попадают ни в одну группу.
BКаждое значение `NULL` образует свою отдельную группу.
CВсе строки с `NULL` попадают в одну общую группу.
DЗапрос всегда завершится ошибкой, если в колонке есть `NULL`.
Ответ: Все строки с `NULL` в колонке группировки попадают в одну группу.

При выполнении `GROUP BY` значения `NULL` считаются равными друг другу. Поэтому все строки, где значение колонки равно `NULL`, объединяются в одну группу, точно так же, как одинаковые ненулевые значения.

8Нужно получить по каждому менеджеру число выполненных и число отменённых заказов в одной строке результата. Какой подход позволяет это сделать?
AПосчитать количество заказов со статусом «выполнен» и «отменён» по каждому менеджеру в одном запросе
BОтфильтровать строки по статусу перед группировкой через условие в `WHERE`
CСоздать отдельный подзапрос для каждого статуса и соединить результаты
DИспользовать отдельный `GROUP BY`-запрос для каждого значения статуса
Ответ: Конструкция `SUM(CASE WHEN status='done' THEN 1 ELSE 0 END)` внутри `GROUP BY` позволяет «разворачивать» категории в отдельные столбцы без дополнительных подзапросов.

Условная агрегация через `SUM(CASE WHEN ... THEN 1 ELSE 0 END)` или `COUNT(CASE WHEN ... THEN 1 END)` позволяет считать строки по нескольким условиям одновременно внутри одного `GROUP BY`-запроса. Это избавляет от необходимости писать несколько отдельных подзапросов или `JOIN`-ов к одной таблице. В PostgreSQL аналогичный результат даёт синтаксис `FILTER (WHERE ...)`.

9Нужно получить количество заказов по паре (`user_id`, `status`) из таблицы `orders`. Какой запрос верный?
A`SELECT user_id, status, COUNT(*) FROM orders GROUP BY user_id;`
B`SELECT user_id, status, COUNT(*) FROM orders GROUP BY user_id, status;`
C`SELECT COUNT(user_id, status) FROM orders GROUP BY user_id, status;`
D`SELECT user_id, status, COUNT(*) FROM orders;`
Ответ: При группировке по нескольким полям все они должны быть перечислены в `GROUP BY`.

Чтобы посчитать количество строк по комбинации значений, нужно указать все столбцы комбинации в `GROUP BY`. В нашем случае: `SELECT user_id, status, COUNT(*) FROM orders GROUP BY user_id, status;`.

10Нужно посчитать сумму оплаченных заказов по каждому пользователю. В таблице `orders` есть поля `user_id`, `amount`, `status`. Какой запрос корректен и наиболее эффективен?
A`SELECT user_id, SUM(amount) FROM orders GROUP BY user_id HAVING status = 'paid';`
B`SELECT user_id, SUM(amount) FROM orders WHERE status = 'paid' GROUP BY user_id;`
C`SELECT user_id, SUM(amount) FROM orders GROUP BY user_id WHERE status = 'paid';`
D`SELECT user_id, SUM(amount) FROM orders HAVING status = 'paid' GROUP BY user_id;`
Ответ: `WHERE` фильтрует строки до группировки, а `HAVING` — агрегированные группы.

Фильтрацию по обычному полю `status` лучше делать в `WHERE`, чтобы отбрасывать лишние строки до агрегации. Корректный вариант: `SELECT user_id, SUM(amount) FROM orders WHERE status = 'paid' GROUP BY user_id;`.

1234567

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

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

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

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

Даты и времяEXPLAIN и оптимизацияВыражения и NULLJOIN и операции множествОсновы SQL-запросовСтроки и приведение типовПодзапросы и CTEОконные функции