SQLLab
Все статьи

Топ-20 вопросов по SQL на собеседовании с ответами

Самые частые SQL-вопросы на собеседованиях для аналитиков и разработчиков: JOIN, GROUP BY, оконные функции, индексы, транзакции. С примерами и объяснениями.

9 марта 2026 г.·6 мин чтения·

Собрали вопросы, которые чаще всего задают на собеседованиях аналитикам данных, backend-разработчикам и Data Engineers. Для каждого — короткий, точный ответ.

Основы

1. Чем отличается WHERE от HAVING?

WHERE фильтрует строки до группировки. HAVING фильтрует группы после GROUP BY.

SELECT city, COUNT(*) AS cnt
FROM orders
WHERE status = 'paid'      -- до группировки
GROUP BY city
HAVING COUNT(*) > 10;      -- после группировки

2. Что такое NULL и как с ним работать?

NULL — отсутствие значения. Любое сравнение с NULL возвращает NULL (не TRUE/FALSE). Проверять нужно через IS NULL / IS NOT NULL.

WHERE phone IS NULL          -- ✅
WHERE phone = NULL           -- ❌ всегда вернёт 0 строк

3. В чём разница между DELETE, TRUNCATE и DROP?

КомандаЧто делаетОткат (ROLLBACK)
DELETEУдаляет строки с условиемДа
TRUNCATEУдаляет все строки, быстро, сбрасывает счётчики SEQUENCEВ большинстве БД — нет
DROPУдаляет таблицу целикомНет

4. Что такое первичный ключ (PRIMARY KEY)?

Уникальный идентификатор строки. Не может быть NULL. На него автоматически создаётся индекс. Таблица может иметь только один PRIMARY KEY (но составной — из нескольких столбцов).

JOIN

5. Какие виды JOIN существуют?

  • INNER JOIN — строки, которые есть в обеих таблицах
  • LEFT JOIN — все строки из левой + совпадения из правой (NULL если нет)
  • RIGHT JOIN — все из правой + совпадения из левой
  • FULL JOIN — все строки из обеих таблиц
  • CROSS JOIN — декартово произведение (каждая строка × каждую)

6. Что вернёт LEFT JOIN если в правой таблице нет совпадений?

NULL для всех столбцов правой таблицы.

SELECT u.name, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- Пользователи без заказов: name = 'Иван', amount = NULL

7. Как найти строки, которые есть в одной таблице, но нет в другой?

-- Через LEFT JOIN
SELECT u.id FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.user_id IS NULL;

-- Через NOT EXISTS (часто быстрее)
SELECT id FROM users u
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);

Агрегация и группировка

8. Почему нельзя использовать агрегатные функции в WHERE?

WHERE выполняется до агрегации — значений SUM(), COUNT() ещё нет. Используй HAVING.

9. Что делает COUNT(*) vs COUNT(col)?

  • COUNT(*) — считает все строки включая NULL
  • COUNT(col) — считает только строки где col != NULL
  • COUNT(DISTINCT col) — количество уникальных ненулевых значений

COUNT(1) работает так же, как COUNT(*) — разницы в производительности нет, это вопрос стиля.

10. Как посчитать процент от общего итога?

SELECT
    category,
    SUM(amount) AS revenue,
    ROUND(100.0 * SUM(amount) / SUM(SUM(amount)) OVER (), 2) AS pct
FROM orders
GROUP BY category;

Оконные функции

11. Чем оконные функции отличаются от GROUP BY?

GROUP BY схлопывает строки. Оконные функции оставляют все строки, добавляя вычисляемое значение.

-- GROUP BY: 1 строка на отдел
SELECT department, AVG(salary) FROM employees GROUP BY department;

-- Оконная: все строки + средняя по отделу рядом
SELECT name, salary, AVG(salary) OVER (PARTITION BY department) AS dept_avg
FROM employees;

12. Чем RANK() отличается от DENSE_RANK() и ROW_NUMBER()?

ФункцияПри одинаковых значениях
ROW_NUMBER()Уникальный номер, произвольный порядок
RANK()Одинаковый ранг, пропускает следующий (1,1,3)
DENSE_RANK()Одинаковый ранг, без пропусков (1,1,2)

ROW_NUMBER() — когда нужен ровно один результат на группу (топ-1). RANK() — для рейтингов с учётом мест (несколько победителей). DENSE_RANK() — когда пропуски в нумерации нежелательны (призовые места: 1, 2, 3 без пропусков).

13. Что такое LAG и LEAD?

LAG(col, n) — значение из предыдущей строки (на n позиций назад). LEAD(col, n) — значение из следующей строки.

SELECT date, revenue,
       LAG(revenue) OVER (ORDER BY date) AS prev_revenue,
       revenue - LAG(revenue) OVER (ORDER BY date) AS delta
FROM daily_stats;

Подзапросы и CTE

14. В чём разница между подзапросом и CTE?

CTE (WITH) — именованный подзапрос, определяется один раз и может переиспользоваться. Лучше читается. Поддерживает рекурсию.

15. Что такое коррелированный подзапрос?

Подзапрос, который ссылается на столбец из внешнего запроса. Выполняется для каждой строки внешнего запроса — может быть медленным.

SELECT name, salary
FROM employees e
WHERE salary > (
    SELECT AVG(salary) FROM employees WHERE department = e.department
);

Индексы и производительность

16. Зачем нужны индексы?

Ускоряют поиск и сортировку. Без индекса — полное сканирование таблицы (seq scan). С индексом — поиск по B-tree.

Минус: индексы замедляют INSERT/UPDATE/DELETE и занимают место.

Особенно эффективны индексы на столбцах с высокой селективностью (много уникальных значений). Индекс на поле с тремя значениями (status, gender) обычно бесполезен — планировщик выберет seq scan.

17. Когда индекс не используется?

  • Функция над индексированным столбцом: WHERE LOWER(name) = 'иван'
  • Неявное приведение типов: WHERE id = '123' (id — integer)
  • LIKE '%суффикс%' (но LIKE 'префикс%' — использует)
  • Слишком маленькая таблица — дешевле seq scan
  • OR между индексированным и неиндексированным столбцом — планировщик может проигнорировать индекс

18. Что такое EXPLAIN и зачем он нужен?

EXPLAIN показывает план выполнения запроса: как БД будет его выполнять, какие индексы использует, ожидаемое количество строк.

EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 42;

ANALYZE — выполняет запрос и показывает реальное время.

Транзакции

19. Что такое ACID?

  • Atomicity — всё или ничего
  • Consistency — данные остаются корректными
  • Isolation — транзакции не мешают друг другу
  • Durability — после COMMIT данные сохранены

20. Что такое уровни изоляции транзакций?

УровеньГрязное чтениеНеповторяемое чтениеФантомное чтение
READ UNCOMMITTED✅ возможно
READ COMMITTED✅ возможно
REPEATABLE READ✅ возможно
SERIALIZABLE

По умолчанию в PostgreSQL — READ COMMITTED.

В PostgreSQL REPEATABLE READ также защищает от фантомного чтения в рамках одного запроса благодаря snapshot isolation, но не от аномалий сериализации при конкурентных вставках.


Хочешь проверить себя? Попробуй решить задачи по этим темам в нашем тренажёре — там 150+ задач с разбором.

Похожие статьи

Попробуй на практике

Тренажёр с реальными задачами — бесплатно и без регистрации

Открыть тренажёр →