Какой уровень SQL нужен, чтобы пройти собес на продуктового аналитика
SQL-секцию заваливают не те, кто не знает SQL. Заваливают те, кто знает его на бумаге: читал про JOIN, смотрел разборы оконных функций, а руками решил полторы задачи. На собесе это видно за пять минут — по паузам, по попытке отфильтровать агрегат в WHERE, по молчанию у экрана.
Планка при этом не космическая. Продуктовому аналитику не нужен уровень дата-инженера — нужен вполне конкретный набор, который набивается за пару месяцев. Ниже разложу, что именно проверяют, и решу четыре задачи того же формата, что дают на секции.
Сколько SQL хватает
Первый — то, без чего разговор даже не начинается. SELECT с фильтрами, JOIN и понимание разницы между LEFT и INNER, GROUP BY с агрегатами, HAVING, сортировки. Спотыкаешься здесь — секция закончилась.
Второй вытягивает середину и закрывает офферы уровня Junior–Middle. Оконные функции (ROW_NUMBER, RANK, LAG и LEAD, нарастающий итог), CTE, DATE_TRUNC с интервалами, условная агрегация через CASE. Именно тут живут продуктовые задачи: когорты, retention, воронки.
Третий — плюс в карму. Дедупликация, чтение плана запроса, ловушки NOT IN с NULL.
Что должно отскакивать от зубов
Прогони себя по списку честно. Не «вспомнить синтаксис», а писать сразу, без гугла:
JOIN нескольких таблиц — и чтобы ты замечал, когда строки начинают дублироваться. GROUP BY с HAVING и внятная разница между WHERE и HAVING. ROW_NUMBER для дедупликации и «первого/второго по порядку». LAG для сравнения с прошлым периодом. CTE, чтобы резать сложный запрос на читаемые куски. DATE_TRUNC для помесячной агрегации. CASE внутри SUM для воронок. И NULL — IS NULL, COALESCE и почему NOT IN иногда ничего не возвращает.
Четыре задачи с собеса и как их решать
Схема простая, держи в голове: orders (id, user_id, amount, status, paid_at), order_items (order_id, product_id, price, qty), products (id, category_id), events (user_id, event_date). Такие же задачи, только с автопроверкой в браузере, лежат в SQL-тренажёре Заскуль Питона (https://zasqlpython.ru/sql-sandbox) — первые открыты без регистрации.
Задача 1. Категории с выручкой выше порога
Формулировка: выведи категории, где суммарная выручка по оплаченным заказам больше миллиона, по убыванию. Смотрят джойн трёх таблиц, группировку и HAVING.
Вся суть — куда что положить. Порог на сумму идёт в HAVING, потому что фильтруем уже посчитанные группы. А status = 'paid' — в WHERE: это про строки, до группировки. Перепутаешь местами — не соберётся.
Задача 2. Второй заказ каждого пользователя
Формулировка: для каждого пользователя найди его второй по времени заказ. Любимая проверка на оконки — и на то, понимаешь ли ты, почему её нельзя фильтровать в лоб.
ROW_NUMBER нумерует заказы внутри каждого пользователя по дате. Обернуть в подзапрос обязательно: оконная функция считается уже после WHERE, так что фильтр rn = 2 живёт только на внешнем уровне. Вот на этом и подлавливают — половина кандидатов пишет WHERE ROW_NUMBER()... = 2 и удивляется ошибке.
Задача 3. Месячный retention когорты
Формулировка: посчитай, какая доля пользователей, впервые пришедших в месяце, вернулась в следующем. Самая продуктовая задача секции — тут сразу и когорты, и CTE, и даты.
Читается по шагам. Первый CTE — месяц первого визита каждого (это и есть когорта). Второй — все месяцы, когда человек был активен. Дальше считаем размер когорты и сколько из неё вернулось ровно через месяц. Напишешь это без запинки — второй уровень у тебя закрыт.
Задача 4. Рост выручки месяц к месяцу
Формулировка: выручка по месяцам и её прирост в процентах к предыдущему. Проверяют LAG и аккуратность с делением.
LAG подтягивает выручку прошлого месяца в ту же строку — дальше обычная арифметика. И вот тут интервьюер почти всегда спрашивает про край: первый месяц даст NULL, а если в прошлом месяце была нулевая выручка — деление на ноль. Проговоришь это сам, до вопроса, — считай, балл в кармане.
На чём сыпятся чаще всего
Из раза в раз одно и то же. Путают WHERE и HAVING — тянут агрегат в WHERE. Фильтруют оконку в том же запросе, забыв про подзапрос. Не замечают, как джойн с дублями раздувает SUM. Ловят пустой результат на NOT IN, где в списке затесался NULL. И самое частое — молчат. Пишут в тишине, будто на экзамене. А интервьюер оценивает не идеальный синтаксис, а то, как ты рассуждаешь. Думай вслух — это буквально половина оценки.
Как это натренировать
Никакой магии: SQL закрепляется руками. Двадцать решённых задач дают больше, чем пять просмотренных курсов.
Если начинаешь с нуля — бери бесплатный курс «SQL с нуля» (https://zasqlpython.ru/course): десять частей от SELECT до оконных функций, всё решается прямо в браузере, базу ставить не надо.
Когда база есть — набивай руку на задачах с автопроверкой. В тренажёре (https://zasqlpython.ru/sql-sandbox) больше пятисот задач с реальных собеседований, движок PostgreSQL прямо в браузере, решение проверяется само.
Перед самим собесом прогони разборы вопросов с собеседований (https://zasqlpython.ru/interviews).
Если честно, четыре задачи выше — это и есть репрезентативный срез. Решаешь их без подсказок минут за пятнадцать — иди на собес спокойно, SQL тебя там не удивит.