Вопросы по SQL на собеседовании 2026 — Junior
S.
Sobes AI

Вопросы по SQL на собеседовании — часть 1/3: Junior с разбором ответов

14.03.2026 | 4 мин чтения | 8 просмотров

Это часть 1 из 3. Часть 2: Middle → | Часть 3: Senior →

Вопросы по SQL на собеседовании — часть 1/3: Junior с разбором ответов

TL;DR: 8 вопросов по SQL, которые стабильно задают джуниорам на собеседованиях — по отзывам с Glassdoor, Хабра и анализу 9 000+ технических интервью за 2024–2026. Для каждого: что на самом деле проверяют, как ответить и где кандидаты ошибаются.

Как пользоваться: Открой перед собеседованием → пройдись по каждому вопросу → попробуй ответить ДО того, как прочитаешь разбор → проверь follow-up. Если follow-up вызывает затруднение — это зона роста.

Эта подборка — не пересказ документации. Это вопросы, которые реально звучат на собеседованиях по SQL в 2024–2026 годах — по данным Glassdoor, тредов на Reddit и анализу вакансий на HH и Хабре. SQL входит в топ-4 тем на технических интервью: по данным анализа 9 247 собеседований, вопросы по базам данных и SQL встречаются в 11% всех технических интервью, а задачи на оптимизацию запросов — в 19% бэкенд-собесов.

Для каждого вопроса: что интервьюер на самом деле проверяет, как ответить, пример кода и где большинство кандидатов ошибается.

Серия из трёх частей: Junior (эта статья) → MiddleSenior. Начнём с базы.

Содержание


1. Что такое PRIMARY KEY и FOREIGN KEY?

Интервьюер проверяет: понимаешь ли ты основы реляционной модели и связи между таблицами.

PRIMARY KEY — столбец (или комбинация столбцов), который однозначно идентифицирует каждую строку в таблице. Два правила: значения уникальны и не могут быть NULL.

FOREIGN KEY — столбец, который ссылается на PRIMARY KEY другой таблицы. Обеспечивает ссылочную целостность: нельзя вставить значение, которого нет в родительской таблице.

CREATE TABLE departments (
    id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);

CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    department_id INT,
    FOREIGN KEY (department_id) REFERENCES departments(id)
);

Теперь нельзя добавить сотрудника с department_id = 999, если в departments нет записи с id = 999.

Типичная ошибка: говорят, что PRIMARY KEY — это всегда один столбец. На самом деле ключ может быть составным:

CREATE TABLE order_items (
    order_id INT,
    product_id INT,
    quantity INT,
    PRIMARY KEY (order_id, product_id)
);

Follow-up: Может ли таблица существовать без PRIMARY KEY? Технически — да, СУБД не запрещает. Но на практике это антипаттерн: без PK невозможно однозначно идентифицировать строку.


2. В чём разница между WHERE и HAVING?

Интервьюер проверяет: знаешь ли ты порядок выполнения SQL-запроса.

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

-- WHERE: отбираем только заказы за 2025 год
SELECT customer_id, COUNT(*) AS order_count
FROM orders
WHERE created_at >= '2025-01-01'
GROUP BY customer_id;

-- HAVING: из результатов оставляем только тех, у кого > 5 заказов
SELECT customer_id, COUNT(*) AS order_count
FROM orders
WHERE created_at >= '2025-01-01'
GROUP BY customer_id
HAVING COUNT(*) > 5;

Типичная ошибка: пытаются использовать агрегатную функцию в WHERE:

-- Так НЕ работает
SELECT customer_id, COUNT(*) AS order_count
FROM orders
WHERE COUNT(*) > 5  -- ошибка!
GROUP BY customer_id;

WHERE выполняется ДО GROUP BY — на этом этапе агрегатных значений ещё нет.

Follow-up: Можно ли использовать WHERE и HAVING в одном запросе? Да, и это нормальная практика: WHERE отсекает ненужные строки до группировки (что ускоряет запрос), а HAVING фильтрует уже агрегированные результаты.


3. Какие типы JOIN существуют?

Интервьюер проверяет: умеешь ли ты соединять таблицы и понимаешь ли, когда какой JOIN использовать.

Пять основных типов:

INNER JOIN — только строки, где есть совпадение в обеих таблицах.

LEFT JOIN — все строки из левой таблицы + совпадения из правой (NULL, если совпадения нет).

RIGHT JOIN — зеркало LEFT JOIN: все строки из правой таблицы.

FULL JOIN — все строки из обеих таблиц, NULL где совпадений нет.

CROSS JOIN — декартово произведение: каждая строка первой таблицы соединяется с каждой строкой второй.

-- Все сотрудники с их отделами (даже если отдел не назначен)
SELECT e.name, d.name AS department
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id;

Типичная ошибка: ставят условие фильтрации правой таблицы LEFT JOIN в WHERE вместо ON:

-- НЕПРАВИЛЬНО: LEFT JOIN превращается в INNER JOIN
SELECT e.name, d.name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id
WHERE d.active = true;  -- отсекает строки с NULL!

-- ПРАВИЛЬНО: условие в ON
SELECT e.name, d.name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id AND d.active = true;

Это одна из самых частых ошибок на собеседованиях по SQL (по данным InterviewQuery и разборам на Хабре).

Follow-up: Если таблица A имеет 10 строк, а B — 100, сколько строк вернёт LEFT JOIN из A в B? Минимум 10 (если связь один-к-одному или нет совпадений). Но может быть больше, если связь один-ко-многим.


Мы разобрали связи между таблицами и фильтрацию. Дальше — группировка, удаление данных и работа с NULL. Это то, на чём чаще всего спотыкаются джуниоры.


4. Как работает GROUP BY?

Интервьюер проверяет: умеешь ли ты агрегировать данные и понимаешь ли, как GROUP BY связан с SELECT.

GROUP BY группирует строки с одинаковыми значениями в указанных столбцах. После группировки можно применять агрегатные функции: COUNT, SUM, AVG, MAX, MIN.

-- Количество сотрудников в каждом отделе
SELECT department_id, COUNT(*) AS employee_count
FROM employees
GROUP BY department_id;

-- Средняя зарплата по городам, только города с > 10 сотрудников
SELECT city, AVG(salary) AS avg_salary
FROM employees
GROUP BY city
HAVING COUNT(*) > 10
ORDER BY avg_salary DESC;

Типичная ошибка: добавляют в SELECT столбец, которого нет в GROUP BY и который не обёрнут в агрегатную функцию:

-- Ошибка: name не в GROUP BY и не в агрегатной функции
SELECT department_id, name, COUNT(*)
FROM employees
GROUP BY department_id;

MySQL в режиме по умолчанию (до 5.7) это пропускал, возвращая случайное значение name. PostgreSQL и современный MySQL с ONLY_FULL_GROUP_BY — выдадут ошибку.

Follow-up: Чем GROUP BY отличается от DISTINCT? GROUP BY группирует строки для агрегации, DISTINCT просто убирает дубликаты. Если нужна только уникальность без агрегатных функций — используй DISTINCT.


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

Интервьюер проверяет: понимаешь ли ты уровни «разрушительности» операций и их связь с транзакциями.

  • DELETE — DML-операция. Удаляет строки по условию. Можно откатить (ROLLBACK). Срабатывают триггеры. Медленнее.

  • TRUNCATE — DDL-операция. Удаляет ВСЕ строки. В большинстве СУБД нельзя откатить (в PostgreSQL — можно, если внутри транзакции). Триггеры не срабатывают. Быстрее.

  • DROP — DDL-операция. Удаляет таблицу целиком: данные, структуру, индексы. Необратимо.

DELETE FROM orders WHERE created_at < '2020-01-01';  -- удалить старые заказы
TRUNCATE TABLE temp_logs;                             -- очистить таблицу логов
DROP TABLE IF EXISTS legacy_data;                     -- удалить таблицу

Типичная ошибка: говорят, что TRUNCATE нельзя откатить — это зависит от СУБД. В PostgreSQL TRUNCATE транзакционный, в MySQL (InnoDB) — нет.

Follow-up: DELETE без WHERE удалит все строки. Чем это отличается от TRUNCATE? DELETE без WHERE — строка за строкой, с логированием каждой. TRUNCATE — сбрасывает страницы данных разом. На большой таблице разница в скорости — десятки раз.


6. Что такое NULL и почему = NULL не работает?

Интервьюер проверяет: понимаешь ли ты трёхзначную логику SQL.

NULL — это не ноль и не пустая строка. Это отсутствие значения. Любое сравнение с NULL возвращает UNKNOWN (не TRUE и не FALSE).

-- Так НЕ работает
SELECT * FROM users WHERE middle_name = NULL;  -- вернёт 0 строк!

-- Правильно
SELECT * FROM users WHERE middle_name IS NULL;
SELECT * FROM users WHERE middle_name IS NOT NULL;

Для подстановки значения вместо NULL используй COALESCE:

SELECT name, COALESCE(middle_name, 'не указано') AS middle_name
FROM users;

Типичная ошибка: забывают про NULL в NOT IN:

-- Опасно! Если в подзапросе есть NULL, результат — 0 строк
SELECT * FROM products
WHERE category_id NOT IN (SELECT category_id FROM hidden_categories);
-- Если hidden_categories содержит NULL — запрос вернёт пустой результат

-- Безопасно
SELECT * FROM products
WHERE category_id NOT IN (
    SELECT category_id FROM hidden_categories WHERE category_id IS NOT NULL
);

Follow-up: Что вернёт NULL + 5? NULL. Что вернёт NULL = NULL? UNKNOWN. Любая арифметика и сравнение с NULL даёт NULL/UNKNOWN.


Осталось два вопроса — про объединение результатов и поиск дубликатов. Это практические задачи, которые часто дают прямо на собесе.


7. В чём разница между UNION и UNION ALL?

Интервьюер проверяет: думаешь ли ты о производительности при написании запросов.

Оба оператора объединяют результаты двух SELECT-запросов. Разница:

  • UNION — убирает дубликаты (выполняет DISTINCT). Дороже по ресурсам.
  • UNION ALL — оставляет все строки как есть. Быстрее.
-- UNION: уникальные города из двух таблиц
SELECT city FROM customers
UNION
SELECT city FROM suppliers;

-- UNION ALL: все города, включая повторы (быстрее)
SELECT city FROM customers
UNION ALL
SELECT city FROM suppliers;

Типичная ошибка: используют UNION по умолчанию, когда дубликаты невозможны или неважны. Это лишняя сортировка и расход ресурсов.

Правило: если не нужна дедупликация — всегда UNION ALL.

Follow-up: Какие требования к запросам в UNION? Одинаковое количество столбцов и совместимые типы данных в каждой позиции.


8. Как найти дубликаты в таблице?

Интервьюер проверяет: можешь ли ты решить практическую задачу, а не просто знаешь теорию.

Классическая задача. GROUP BY + HAVING COUNT > 1:

-- Найти дублирующиеся email
SELECT email, COUNT(*) AS cnt
FROM users
GROUP BY email
HAVING COUNT(*) > 1;

Если нужны сами строки с дубликатами (не только значения):

SELECT u.*
FROM users u
JOIN (
    SELECT email
    FROM users
    GROUP BY email
    HAVING COUNT(*) > 1
) dupes ON u.email = dupes.email
ORDER BY u.email;

Типичная ошибка: забывают, что «дубликат» может быть по комбинации столбцов, а не по одному:

-- Дубликаты по комбинации имя + телефон
SELECT first_name, phone, COUNT(*)
FROM contacts
GROUP BY first_name, phone
HAVING COUNT(*) > 1;

Follow-up: Как удалить дубликаты, оставив одну запись? Используй CTE с ROW_NUMBER (это уже Middle-уровень, разберём в части 2).


Итого Junior: 8 вопросов. Фокус — ключи, JOIN, GROUP BY, NULL, удаление данных. Если уверенно отвечаешь на follow-up — база у тебя крепкая. Если NULL + NOT IN стал сюрпризом — перечитай вопрос 6.


Как попробовать Sobes AI

Sobes AI — ИИ-ассистент, который помогает на техническом собеседовании в реальном времени. Подсказывает ответы, пока ты общаешься с интервьюером.

  1. Зайди на sobesai.app и скачай приложение
  2. Запусти перед собеседованием
  3. Sobes AI слушает вопрос и подсказывает структурированный ответ
  4. Работает с SQL, базами данных и другими техническими темами

Это часть 1 из 3. Часть 2: Middle → | Часть 3: Senior →

Готовитесь к собеседованию?

Sobes AI слушает вопросы интервьюера и генерирует ответы в реальном времени.

Скачать Sobes AI