Talanto
For recruiters
PlansCV Review
Login

Categories

  • All articles
  • Job Search
  • Resume & CV
  • Cover Letters & Applications
  • Interviews
  • Salary & Offers
  • Job Reviews & Roundups
  • Remote Work
  • Career
  • Career Growth
  • Market Trends
  • Onboarding
  • Tips

Related articles

  • Как отвечать на вопрос о зарплатных ожиданиях

    57d ago

  • Тестовое задание при найме: как оценить объём, выполнить и представить результат

    57d ago

  • Как ответить на вопрос «Почему вы хотите работать у нас?»

    57d ago

  • Как рассказать о сильных сторонах на собеседовании

    57d ago

  • Как говорить о слабых сторонах на собеседовании

    57d ago

Looking for a job?

IT roles with remote and relocation options.

Browse jobs
  1. Articles
  2. Interviews

Вопросы SQL на собеседовании: как готовиться

Джойны, окна, индексы, объяснение плана. Набор задач, которые реально ставят аналитикам и backend.

9 min readApril 23, 202668 views

On this page
  1. Какой уровень на какую роль
  2. JOIN: задача, которую ставят всегда
  3. Группировка, HAVING, подзапрос
  4. Окна: «последний статус» и дедуп
  5. Индекс и «почему тормозит»
  6. NULL, дубли, аккуратность
  7. Как решать вслух за 15 минут
  8. Воронка и повторные покупки — скетч для аналитика
  9. Неделя практики без «100 задач с литкода SQL»
  10. Частые вопросы
  11. Что сделать сейчас

SQL на собеседовании в 2026-м редко проваливается из-за «не назвал все виды JOIN из учебника». Чаще ломается другое: человек пишет SELECT * и надеется, что интервьюер догадается. Нанимающий аналитика, backend или QA хочет увидеть, что вы умеете собрать нужные строки, не удвоить их джойном и объяснить, почему запрос может тормозить. Это проверка мышления на данных, не олимпиада по стандарту SQL:2016.

Ниже — темы, которые реально ставят, полные скетчи запросов в цитатах и как практиковаться на живой схеме, а не на мемах про DELETE без WHERE. Карта обучения — SQL roadmap. Общий каркас интервью — вопросы на собеседовании. Роли, где SQL в явном виде: вакансии с SQL.

Коротко:

  • INNER/LEFT, условие в ON vs WHERE, размножение строк — база, без которой окна рано.
  • GROUP BY и HAVING — разные этажи фильтра. Окна — «оставить строки, добавить ранг/сумму».
  • Индекс и план: гипотеза, EXPLAIN, селективность. Не «надо кэш» первым словом.
  • Пишите читаемый запрос: явные JOIN, понятные алиасы, без SELECT * в финале.
  • Готовьте 3–4 запроса по своей предметке: список, агрегат, «последняя запись», дедуп.

Какой уровень на какую роль

QA: найти заказы пользователя, посчитать, проверить, что UI совпал с таблицей. Аналитик: воронка, повторные покупки, окна по дате. Backend: тот же JOIN плюс транзакция и «почему seq scan». Data engineer — ещё инкремент и качество. Не готовьте аналитические окна на QA-слот, если в вакансии «написать SELECT». Не приходите на аналитика только с SELECT по одной таблице.

Диалект: Postgres чаще на CIS product, иногда MySQL/ClickHouse. Синтаксис окон почти везде похож. Если в вакансии ClickHouse — готовьте движок и ограничения JOIN, не притворяйтесь, что это тот же Postgres.

JOIN: задача, которую ставят всегда

Формулировка: «пользователи и заказы. Вывести всех пользователей и сумму оплаченных заказов за 90 дней. У кого заказов нет — ноль, не пропасть из списка».

SELECT u.id, u.email, COALESCE(SUM(o.amount), 0) AS paid_90d FROM users u LEFT JOIN orders o ON o.user_id = u.id AND o.status = 'paid' AND o.created_at >= CURRENT_DATE - INTERVAL '90 days' GROUP BY u.id, u.email;

Почему LEFT: INNER выкинет пользователей без оплат. Почему фильтр дат и статуса в ON, не в WHERE: условие на o в WHERE после LEFT превращает его в INNER — строки с NULL-заказом отвалятся. COALESCE, чтобы в отчёте был 0, не NULL, если так просит заказчик.

Риск размножения: если у заказа несколько строк позиций и я по ошибке джойню items без агрегата — сумма раздуется. Тогда либо сначала агрегировать заказы в подзапросе, либо считать SUM по уникальному order_id аккуратно. На интервью я это проговариваю, не жду, пока найдут за меня.

Второй классический вопрос: «разница JOIN в ON и фильтр в WHERE». Ответ выше. Третий: «нарисуйте, сколько строк получится» на маленькой таблице — потренируйте на бумаге.

Группировка, HAVING, подзапрос

«Клиенты, у которых больше трёх оплаченных заказов за месяц».

SELECT user_id, COUNT(*) AS paid_cnt FROM orders WHERE status = 'paid' AND created_at >= DATE_TRUNC('month', CURRENT_DATE) GROUP BY user_id HAVING COUNT(*) > 3;

WHERE режет строки до группировки. HAVING — группы после. Писать HAVING на сырую дату вместо WHERE — ошибка: движок сначала тащит лишнее. Подзапрос уместен, если дальше джойнить к users за email: сначала ids, потом справочник, чтобы не тащить email в GROUP BY зря, если диалект требует все неагрегированные поля.

Окна: «последний статус» и дедуп

Формулировка: «по каждому заказу последняя строка из истории статусов».

WITH ranked AS ( SELECT s.order_id, s.status, s.changed_at, ROW_NUMBER() OVER (PARTITION BY s.order_id ORDER BY s.changed_at DESC, s.id DESC) AS rn FROM order_status_history s ) SELECT order_id, status, changed_at FROM ranked WHERE rn = 1;

ROW_NUMBER, не RANK, если коллизия по времени: RANK даст две «последние». Второй ключ id — стабильный тай-брейк. Альтернатива DISTINCT ON (order_id) в Postgres: SELECT DISTINCT ON (order_id) order_id, status, changed_at FROM order_status_history ORDER BY order_id, changed_at DESC, id DESC; — короче, менее переносимо. На интервью называю оба и спрашиваю, какой диалект у них.

SUM() OVER (PARTITION BY user_id ORDER BY created_at) — накопительно. Не путать с GROUP BY: строки не схлопываются. Если попросили «топ-3 заказа на пользователя» — тот же ROW_NUMBER, затем WHERE rn <= 3.

Это не трюк взлома и не «достать чужие данные». Это отчётный паттерн, который ждут аналитики и backend.

Индекс и «почему тормозит»

Вопрос: «список заказов пользователя по дате, таблица большая. Что смотрите?»

Сначала тот же запрос в EXPLAIN ANALYZE, не оптимизация вслепую. Смотрю seq scan vs index scan, сколько строк читаем vs сколько отдаём. Фильтр user_id + сортировка created_at — гипотеза: составной индекс (user_id, created_at). Отдельный индекс только по дате часто бесполезен для «моего пользователя».

SELECT o.id, o.created_at, o.status FROM orders o WHERE o.user_id = 1042 ORDER BY o.created_at DESC LIMIT 50;

Не тяну JOIN на историю статусов, если на списке три поля шапки. Кэш — после того, как запрос дешёвый. Иначе кэшируем медленный мусор. Честно: без селективности не обещаю «композитный всегда». Могу предложить гипотезу и проверку на копии, не создавать индекс на каждый столбец — запись тоже стоит.

Не предлагайте «выключить seq scan глобально» и не рассказывайте, как обходить права. План и индекс — достаточно.

NULL, дубли, аккуратность

COUNT(*) считает строки, COUNT(col) пропускает NULL. NOT IN с NULL в подзапросе — ловушка, лучше NOT EXISTS. Равенство NULL не через =, а IS NULL. На интервью это отделяют взрослых от тех, кто учил только INNER JOIN по id.

Пользователи без заказа через NOT EXISTS:

SELECT u.id FROM users u WHERE NOT EXISTS ( SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.status = 'paid' );

Эквивалент LEFT JOIN ... WHERE o.id IS NULL. NOT IN (SELECT user_id FROM orders) развалится, если user_id в подзапросе бывает NULL. Это я и скажу, если предложат NOT IN.

CV review

How does your resume look to a recruiter?

Upload a PDF or DOCX. In 1–2 minutes you get a score across 7 sections and fixes in order of impact.

AKAnna KovalevaFrontend · Middle
46

The best result is buried at the end

Worked on developing new features and fixing bugs. Took part in moving the cart to Next.js, after which conversion grew from 2.1% to 2.8%.

Rewrite

Moved the cart to Next.js with the team, lifting conversion from 2.1% to 2.8%.

Review my resumePDF or DOCX · 1–2 minutes

Как решать вслух за 15 минут

  1. Пересказать задачу своими словами и спросить зерно: «без заказов — ноль или не показывать?»
  2. Назвать таблицы и зерно строки результата.
  3. Набросать FROM/JOIN, потом WHERE, потом агрегат или окно.
  4. Проговорить риск удвоения и NULL.
  5. Если успели — индекс под этот паттерн доступа.

Пишите читабельно: один JOIN на строку, не запятые в FROM как в 1998. Интервьюер читает ход мысли. Живой прогон объяснения — в подготовке к интервью.

Воронка и повторные покупки — скетч для аналитика

Если слот аналитический, почти наверняка дадут «конверсия» или «вернувшиеся». Не начинайте с красивого дашборда. Сначала зерно: что считается заказом, какой статус «успех», какое окно возврата.

Доля пользователей с хотя бы одной оплатой за 90 дней:

SELECT COUNT(*) FILTER (WHERE paid_users.user_id IS NOT NULL)::numeric / COUNT(*) AS cr FROM users u LEFT JOIN ( SELECT DISTINCT user_id FROM orders WHERE status = 'paid' AND created_at >= CURRENT_DATE - INTERVAL '90 days' ) paid_users ON paid_users.user_id = u.id WHERE u.registered_at < CURRENT_DATE - INTERVAL '90 days';

Повторная покупка: у кого COUNT(paid) >= 2 за окно. Не среднее по больнице без сегмента новичок/старый. Окно и статус проговариваю до того, как писать. FILTER / DISTINCT в подзапросе — чтобы не раздуть джойном позиций. Если диалект без FILTER — CASE WHEN внутри COUNT.

Ограничение: без витрины это тяжёлый запрос на сырых orders. На интервью скажу, что в проде вынес бы агрегат в ежедневную таблицу, а здесь показываю логику. Не обещаю «ClickHouse за пять минут», если в вакансии Postgres.

Backend-слоту этот отчёт могут не дать — тогда вернитесь к списку по user_id и к «последнему статусу». Не тащите воронку в QA-экран без нужды: вас услышат как человека не на ту роль.

Неделя практики без «100 задач с литкода SQL»

  1. Схема из 4 таблиц: users, orders, items, status_history. Свои 20 строк.
  2. Три запроса: LEFT+SUM, HAVING, последняя запись окном.
  3. EXPLAIN на список по user_id. Сменить индекс, посмотреть план.
  4. Вслух один запрос без редактора, потом сверить.

Свой домен сильнее случайных «сотрудник-отдел» из учебника, если вы бьётесь в заказы или тикеты. Для аналитического портфолио тот же принцип, что в резюме: один разбор с выводом, не галерея дашбордов.

На экране часто дают «исправьте запрос», не «напишите с нуля». Типичные дыры: JOIN без ключа, фильтр на NULL через =, GROUP BY без всех неагрегированных полей в строгом режиме, окно без ORDER BY, LIMIT без ORDER BY. Читайте чужой SQL вслух: что зерно строки, где удвоение. Это тот же навык, что ревью. Не переписывайте всё сразу — сначала назовите баг.

Плохо: SELECT u.email, o.amount FROM users u, orders o WHERE u.id = o.user_id AND o.created_at > '2026-01-01'; — запятая в FROM, нет статуса, дата в строке без таймзоны. Лучше явный JOIN, status = 'paid', timestamptz, и вопрос: «нужны все заказы или только оплаченные». Если в черновике SELECT * — перед сдачей сузьте поля. Интервьюер смотрит, умеете ли вы остановиться, не только умеете ли вы джойнить.

Частые вопросы

01Можно ли гуглить синтаксис на экране?

Спрашивайте правила. Часто можно уточнить DISTINCT ON vs окно. Нельзя — молча открыть готовую шпаргалку на чужую задачу. Честный «в Postgres я бы взял DISTINCT ON, напомню синтаксис» лучше выдуманного Oracle.

02Нужно ли учить NoSQL к SQL-раунду?

Нет, пока его нет в вакансии. Один абзац «когда документ, когда связь» — максимум.

03Что, если я backend и слабо в окнах?

Закройте JOIN, GROUP BY, индекс, транзакцию. Окно — «последняя запись», один паттерн. Этого хватает на многие backend-слоты. На аналитика — окна обязательны.

04Спросят ли про транзакции?

На backend да: isolation одной фразой, не список аббревиатур без сценария двух писателей. На QA — редко глубже «что будет, если два заказа». На аналитика — чаще read-only отчёт.

05Большое тестовое «постройте DWH за выходные»?

Это объём работы. Отказ от тестового, если часов больше лимита.

06Помогает ли сопроводительное?

Короткое: какой отчёт уже строили, ссылка. Сопроводительное, шаблоны — короткое письмо.

Что сделать сейчас

Нарисуйте четыре таблицы своей предметки. Напишите три запроса из этого текста своими именами полей. Проговорите LEFT vs WHERE вслух. Затем смотрите роли в каталоге SQL и готовьте те паттерны, которые в объявлении: отчёт, список API или проверка QA — не все сразу.

Накануне экрана достаточно трёх листков: LEFT+SUM без потери пользователей, «последняя запись» окном, список по user_id с гипотезой индекса. Скажите каждый вслух, не глядя в редактор. Если завтра аналитика — добавьте воронку и определение «успеха». Если QA — хватит SELECT и JOIN на проверку UI. Не тащите чужой «топ-100 SQL вопросов»: интервьюер всё равно даст свою схему.

Next step

Try this article's advice on your own resume

The review highlights the lines where recruiters lose interest and suggests what to write instead.

  • A score out of 100 across 7 sections
  • Ready-made rewrites for weak lines
  • How well you fit a specific vacancy
Review my resumePDF or DOCX · 1–2 minutes
Sample reviewFrontend · Middle
46

Was 46
Now 87 / 100

  • Summary3 → 9
  • Experience4 → 9
  • Skills5 → 9

On this page

  1. Какой уровень на какую роль
  2. JOIN: задача, которую ставят всегда
  3. Группировка, HAVING, подзапрос
  4. Окна: «последний статус» и дедуп
  5. Индекс и «почему тормозит»
  6. NULL, дубли, аккуратность
  7. Как решать вслух за 15 минут
  8. Воронка и повторные покупки — скетч для аналитика
  9. Неделя практики без «100 задач с литкода SQL»
  10. Частые вопросы
  11. Что сделать сейчас

Categories

  • All articles
  • Job Search
  • Resume & CV
  • Cover Letters & Applications
  • Interviews
  • Salary & Offers
  • Job Reviews & Roundups
  • Remote Work
  • Career
  • Career Growth
  • Market Trends
  • Onboarding
  • Tips

Related articles

  • Как отвечать на вопрос о зарплатных ожиданиях

    57d ago

  • Тестовое задание при найме: как оценить объём, выполнить и представить результат

    57d ago

  • Как ответить на вопрос «Почему вы хотите работать у нас?»

    57d ago

  • Как рассказать о сильных сторонах на собеседовании

    57d ago

  • Как говорить о слабых сторонах на собеседовании

    57d ago

Looking for a job?

IT roles with remote and relocation options.

Browse jobs
AboutPublic OfferTerms of ServicePrivacy PolicySupport
AboutPublic OfferTerms of ServicePrivacy PolicySupport

By Region

  • Jobs in Europe
  • Jobs in USA
  • Jobs in Canada
  • Jobs in Russia

By Format

  • Remote Jobs
  • Relocation to USA
  • Hybrid Jobs
  • Office Jobs

By Experience Level

  • Junior Jobs
  • Middle Jobs
  • Senior Jobs