SQL на собеседовании аналитика: что спрашивают
Почему SQL важен
SQL — самый частый практический вопрос на собесах аналитика. В 90% собеседований в tech на middle+ уровне есть SQL-секция.
Даже если в работе вы используете Python/pandas больше, SQL остаётся универсальным языком взаимодействия с данными. От собесного SQL зависит, будет ли offer.
Хорошая новость: репертуар задач ограничен. 20-30 паттернов покрывают 90% вопросов.
Формат SQL-секции
Варьируется:
Live coding. Решаете задачу в онлайн-редакторе (LeetCode, HackerRank, собственный) с screen share. 30-45 минут, 2-3 задачи.
Whiteboard (устно). На whiteboard / в Zoom-chat пишете решения. Интервьюер оценивает логику больше синтаксиса.
Take-home. Даётся 2-24 часа на решение сложной задачи. Реже, но бывает.
В любом формате принцип одинаков: понять задачу, думать вслух, проверить решение.
Типы задач
1. Filtering + aggregation. Самый base level.
«Найди топ 10 клиентов по sum purchases за последний год».
2. Joins. Multiple tables.
«Покажи пользователей и их последнюю покупку».
3. Window functions. Middle+.
«Для каждого пользователя второй заказ», «running total», «rank within group».
4. Date manipulation.
«DAU за последние 30 дней», «users who came back on Day 7».
5. CTE и subqueries.
Структурирование complex queries.
6. Self-joins.
«Пары consecutive purchases», «менеджеры и подчинённые».
7. Pivots.
«Распредели по columns: платформы или категории».
8. Cohort/retention.
«Retention by signup cohort by Day N».
Задача: Top N per group
Классика.
«Для каждого отдела найди 2 самых высокооплачиваемых сотрудника».
Решение через ROW_NUMBER():
WITH ranked AS (
SELECT
department,
name,
salary,
ROW_NUMBER() OVER (
PARTITION BY department
ORDER BY salary DESC
) AS rn
FROM employees
)
SELECT department, name, salary
FROM ranked
WHERE rn <= 2;Вариации:
- RANK() если ties должны получить одинаковый ранг.
- DENSE_RANK() если после tied ranks не пропускать.
Задача: Running total
«Посчитай cumulative sum revenue по дням».
SELECT
DATE,
revenue,
SUM(revenue) OVER (ORDER BY DATE) AS cumulative_revenue
FROM daily_revenue
ORDER BY DATE;Window без PARTITION — по всем rows.
Для per-group running:
SUM(revenue) OVER (PARTITION BY customer_id ORDER BY DATE)Задача: DAU и MAU
«Посчитай DAU на каждый день за последний месяц».
SELECT
DATE(event_time) AS day,
COUNT(DISTINCT user_id) AS dau
FROM events
WHERE event_time >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY DATE(event_time)
ORDER BY day;MAU rolling: 30-дневное окно на каждый день.
WITH daily_users AS (
SELECT DATE(event_time) AS day, user_id
FROM events
GROUP BY DATE(event_time), user_id
)
SELECT
day,
COUNT(DISTINCT user_id) OVER (
ORDER BY day
RANGE BETWEEN INTERVAL '29 days' PRECEDING AND CURRENT ROW
) AS mau_rolling
FROM daily_users;Последнее — advanced. Некоторые СУБД не поддерживают COUNT DISTINCT в window.
Задача: Retention
«Для каждой signup cohort покажи retention на Day 1, 7, 30».
WITH cohorts AS (
SELECT
user_id,
DATE(signup_time) AS signup_date
FROM users
),
activity AS (
SELECT DISTINCT
user_id,
DATE(event_time) AS active_date
FROM events
)
SELECT
c.signup_date AS cohort,
COUNT(DISTINCT c.user_id) AS cohort_size,
COUNT(DISTINCT CASE
WHEN a.active_date = c.signup_date + INTERVAL '1 day' THEN c.user_id
END) * 1.0 / COUNT(DISTINCT c.user_id) AS day_1_retention,
COUNT(DISTINCT CASE
WHEN a.active_date = c.signup_date + INTERVAL '7 days' THEN c.user_id
END) * 1.0 / COUNT(DISTINCT c.user_id) AS day_7_retention
FROM cohorts c
LEFT JOIN activity a ON c.user_id = a.user_id
WHERE c.signup_date >= CURRENT_DATE - INTERVAL '60 days'
GROUP BY c.signup_date
ORDER BY c.signup_date;Задача: Consecutive events
«Найди пользователей с 3 днями подряд активности».
Window trick:
WITH daily_activity AS (
SELECT DISTINCT user_id, DATE(event_time) AS active_day
FROM events
),
numbered AS (
SELECT
user_id,
active_day,
active_day - INTERVAL '1 day' * ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY active_day
) AS streak_group
FROM daily_activity
),
streaks AS (
SELECT
user_id,
streak_group,
COUNT(*) AS streak_length
FROM numbered
GROUP BY user_id, streak_group
)
SELECT DISTINCT user_id
FROM streaks
WHERE streak_length >= 3;Trick: вычитание row_number из даты даёт одинаковый value для consecutive days.
Задача: Second purchase
«Для каждого user найди дату второго заказа».
SELECT
user_id,
order_date AS second_purchase
FROM (
SELECT
user_id,
order_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY order_date
) AS rn
FROM orders
) t
WHERE rn = 2;Вариации: «разница в днях между 1 и 2 purchase» — использовать LAG():
SELECT
user_id,
order_date - LAG(order_date) OVER (
PARTITION BY user_id ORDER BY order_date
) AS days_between
FROM orders;Задача: Median
«Найди медианную зарплату по отделам».
PostgreSQL:
SELECT
department,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary) AS median_salary
FROM employees
GROUP BY department;Без percentile — через window functions:
SELECT DISTINCT
department,
FIRST_VALUE(salary) OVER (
PARTITION BY department
ORDER BY CASE WHEN salary_rank_asc = salary_rank_desc THEN 0
WHEN salary_rank_asc - salary_rank_desc = 1 THEN 0
ELSE 1 END,
ABS(salary_rank_asc - salary_rank_desc)
) AS median
FROM (
SELECT department, salary,
RANK() OVER (PARTITION BY department ORDER BY salary) AS salary_rank_asc,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS salary_rank_desc
FROM employees
) t;Complexity — тест на deep SQL knowledge. Редко прямо в собесе.
Задача: NTH value
«Найди 3-й по величине продажу в каждой категории».
SELECT category, sale_amount
FROM (
SELECT
category,
sale_amount,
DENSE_RANK() OVER (
PARTITION BY category
ORDER BY sale_amount DESC
) AS rnk
FROM sales
) t
WHERE rnk = 3;Задача: Gaps and islands
«Найди пропущенные даты в последовательности».
WITH bounds AS (
SELECT
DATE,
LAG(DATE) OVER (ORDER BY DATE) AS prev_date
FROM events_calendar
)
SELECT
prev_date + INTERVAL '1 day' AS gap_start,
DATE - INTERVAL '1 day' AS gap_end
FROM bounds
WHERE DATE - prev_date > 1;Подготовка к SQL-интервью — главный priority для аналитика. В тренажёре Карьерник собрано 500+ SQL-задач с реальных собесов с разборами и объяснениями.
Популярные задачи по компаниям
Яндекс. Retention, cohort analysis, window functions, date arithmetic.
Тинькофф. Financial aggregations, time series, transactions analysis.
Avito. Listings, user behavior, session analysis, funnels.
Ozon. Orders, inventory, recommendations, conversion funnels.
Сбер. Payments, anti-fraud, financial risks.
Альфа-Банк. Transaction analytics, customer segmentation.
Каждая компания имеет свои любимые типы задач — учитывайте в подготовке.
Live coding tips
1. Думать вслух. «I'd start with... join... then aggregate... filter».
2. Обсудить approach перед кодом. Понять, правильное ли direction.
3. Начать с small example. «Допустим, у нас 3 user, каждый с 2 orders». Проверить query вручную.
4. Проверить edge cases. NULL, дубликаты, zero values, empty results.
5. Читать свой код. «Здесь я группирую по..., фильтрую...». Показывает, что понимаете что написали.
6. Спрашивать про formats. «Даты в string или date type?» «Duplicate rows?» Хороший sign.
Типичные ошибки на собесе
Писать сразу final query. Без обсуждения approach. Рискованно.
Syntax errors из-за panic. Печатать без внимания. Checking решение перед submit.
Не использовать CTE. Сложные nested subqueries. Сложнее читать и debug. CTE are preferred.
Забыть NULL handling. COUNT(*) vs COUNT(col) vs COUNT(DISTINCT col) — разница.
Ignore performance. Для crud собесов нет, но senior-level может спросить «какая была бы сложность?» или «как бы оптимизировать?».
Stuck in silence. Если не знаете answer, talk through thinking. Иногда interviewer даёт hints.
Как готовиться
Решать задачи. LeetCode SQL, StrataScratch, DataLemur. Начните с medium, потом hard.
Paper / whiteboard practice. Не только на компьютере. Некоторые собесы без autocomplete.
Review SQL features. Window functions, regex, JSON operators, CTE — часто missing в beginner knowledge.
Mock interviews. С друзьями или coaches. Real pressure experience.
Reading real interview questions. Glassdoor, specific blogs — хорошая source common patterns.
Читайте также
FAQ
Какой SQL dialect учить?
PostgreSQL — universal baseline. В компании могут быть MySQL, ClickHouse, BigQuery — синтаксис slightly differs.
Нужны ли SQL сертификаты?
Не решающие. Real projects, GitHub, LinkedIn примеры решённых задач — более ценно.
Запоминать все Windows functions?
Main — ROW_NUMBER, RANK, LAG, LEAD, SUM OVER. Остальные — справочно.
Если не знаю синтаксис?
Lookup — OK в take-home. В live — вспомните логически, explain что хотите сделать, interviewer подскажет синтаксис.