Практика SQL
SQL — рабочий язык аналитика: на нём вы достаёте, агрегируете и фильтруете данные ещё до того, как откроете BI-инструмент или Python. На собеседовании первые задачи почти всегда именно такие — «посчитайте», «сгруппируйте», «найдите тех, у кого больше N». За кажущейся простотой прячутся ловушки: агрегат в WHERE, потеря строк с одинаковым максимумом, группировка не по той гранулярности.
Эта тема закрывает два кирпича, на которых стоит весь аналитический SQL: агрегатные функции, сворачивающие много строк в одно число, и связку GROUP BY + HAVING, которая делает то же самое по группам. Разберитесь, в каком порядке СУБД выполняет WHERE, GROUP BY и HAVING, — и большинство ловушек исчезнут сами. Подробности — в слоях ниже.
Карта темы
- Агрегатные функции —
COUNT,SUM,AVG,MIN,MAX, сворачивание строк в одно значение и ловушка с потерей совпадений. - Группировка и HAVING —
GROUP BYпо нужной гранулярности и фильтрHAVING, который умеет ссылаться на агрегат, в отличие отWHERE.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
Ставить агрегат в WHERE (WHERE COUNT(...) > 1) | Ошибка запроса — WHERE выполняется до агрегации и не видит COUNT() |
SELECT MAX(salary), first_name без GROUP BY | Ошибка или произвольная строка — обычный столбец рядом с агрегатом без группировки некорректен |
ORDER BY salary DESC LIMIT 1 для «максимума» | Теряются сотрудники с равным максимумом (ties) |
| Группировать не по той гранулярности | «Больше одного заказа в день» превращается в «за месяц», если забыть день в GROUP BY |
| Путать «выше среднего» с «максимумом» | WHERE salary > AVG(...) возвращает не топ, а половину таблицы |
Значение для собеседований
Аналитический SQL проверяют как базовую грамотность: умеете ли вы думать «множествами строк», а не построчно. Кандидат, который вслух проговаривает порядок выполнения — «сначала WHERE по строкам, потом GROUP BY, потом агрегаты, потом HAVING по группам», — сразу выглядит убедительнее того, кто наугад тасует условия между WHERE и HAVING.
Что обычно проверяют:
- Знаете ли вы, что агрегат считается по группе строк, и почему обычный столбец нельзя смешивать с
MAX()безGROUP BY. - Куда идёт фильтр по агрегату — в
HAVING, а не вWHERE, и почему. - Как сохранить все строки с одинаковым максимумом вместо
LIMIT 1. - Как выбрать гранулярность группировки под формулировку задачи.
Типичный неверный ответ: «поставлю COUNT() > 1 в WHERE». WHERE отрабатывает раньше группировки, и агрегат ещё не существует — условие по счёту живёт только в HAVING.