Большинство SQL-вопросов на QA-интервью сводятся к четырём паттернам: SELECT с WHERE чтобы верифицировать что запись сохранена, LEFT JOIN чтобы найти осиротевшие записи, COUNT с GROUP BY чтобы найти дубликаты, и DELETE чтобы очищать тестовые данные. Интервьюеры хотят практических ответов привязанных к сценариям тестирования, а не учебниковых определений. Статья разбирает десять вопросов которые реально появляются на джуниор, мид и сеньор QA-скринингах, с ответами сформулированными вокруг частых тест-кейсов.

Какой уровень SQL проверяют QA-интервью

Для большинства QA automation-ролей джуниоры должны знать SELECT, WHERE, базовую фильтрацию и понимать что такое JOIN концептуально. Мид-уровень добавляет JOIN (INNER, LEFT), GROUP BY, агрегатные функции (COUNT, SUM, AVG) и подзапросы. Сеньорам ожидаемо знать оконные функции, концепции оптимизации запросов и объяснение планов запросов.

Если в описании вакансии упоминается "database testing" или "data validation": жди более глубоких SQL-вопросов. В остальных случаях типичен уровень джуниор-мид.

Основные вопросы и ответы

1. "Какие SQL-запросы ты используешь чаще всего в тестировании?"

Что хотят услышать: практические кейсы, а не теоретические запросы.

Сильный ответ

"Чаще всего я использую SELECT с WHERE чтобы верифицировать что запись сохранена с правильными значениями, COUNT чтобы проверить количество существующих записей, и LEFT JOIN чтобы проверить связи между таблицами. Например, верифицировать что создание заказа также создало ожидаемые строки order_items. Ещё использую DELETE и INSERT для подготовки и очистки тестовых данных в тестовых окружениях."

2. "Как верифицировать что пользователь был создан корректно после регистрации?"

-- Найти пользователя и проверить ключевые поля
SELECT id, email, role, is_active, created_at
FROM users
WHERE email = 'test_user@example.com';

Затем верифицировать:

  • Строка существует (если 0 строк: регистрация не записала в БД)
  • email совпадает с тем что было отправлено
  • role равен 'member' (не 'admin' по умолчанию)
  • is_active равен false (если требуется подтверждение email до активации)
  • created_at недавний (не ранее существовавшая строка)

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

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

-- WHERE: фильтрует отдельные строки
SELECT user_id, amount FROM orders WHERE status = 'completed';

-- HAVING: фильтрует группы (после GROUP BY)
SELECT user_id, COUNT(*) as order_count
FROM orders
GROUP BY user_id
HAVING COUNT(*) > 5;
-- Возвращает пользователей у которых более 5 заказов

Применение в тестировании: HAVING используется чтобы найти пользователей с дублирующимися записями, заказами выше порога, или любым агрегированным условием.

4. "Объясни разницу между INNER JOIN и LEFT JOIN"

INNER JOIN возвращает строки существующие в ОБЕИХ таблицах: только совпадения. LEFT JOIN возвращает ВСЕ строки из левой таблицы плюс совпадающие строки из правой. Несовпавшие строки правой таблицы имеют NULL-значения.

-- Какие пользователи разместили хотя бы один заказ?
SELECT u.email
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
-- Только пользователи у которых есть заказы

-- Какие пользователи НИКОГДА не размещали заказ?
SELECT u.email
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;
-- Пользователи без совпадающего заказа (проверка на NULL)

Применение в тестировании: LEFT JOIN с WHERE right.id IS NULL: классический паттерн для поиска "осиротевших" записей или верификации что что-то НЕ было создано.

5. "Как найти дублирующиеся записи в таблице?"

SELECT email, COUNT(*) as count
FROM users
GROUP BY email
HAVING COUNT(*) > 1;

Находит email которые встречаются более одного раза. Замени email на любое поле которое должно быть уникальным.

Применение в тестировании: после миграции или импорта данных верифицировать что дублирующиеся записи не были созданы.

6. "В чём разница между DELETE и TRUNCATE?"

| | DELETE | TRUNCATE |

|-|--------|---------|

| Удаляет | Конкретные строки (с WHERE) или все строки | Все строки (WHERE невозможен) |

| Откат | Можно откатить (в транзакции) | Как правило нельзя (DDL-операция) |

| Триггеры | Запускает DELETE-триггеры уровня строк | Не запускает триггеры |

| Скорость | Медленнее для больших таблиц | Намного быстрее |

| Применение в тестировании | Подготовка/очистка конкретных тестовых данных | Сброс целых таблиц между прогонами |

-- Удалить только тестового пользователя
DELETE FROM users WHERE email LIKE 'test_%@example.com';

-- Очистить всю таблицу test_runs между сьютами
TRUNCATE TABLE test_runs;

7. "Как ты используешь SQL для подготовки тестовых данных?"

Сильный ответ

"Я использую INSERT чтобы создавать тестовых пользователей, заказы или любые предварительные данные в тестовых окружениях. Ещё использую SELECT чтобы подтверждать предусловия до запуска теста: например, проверяю что пользователь которого я собираюсь тестировать не имеет уже существующего аккаунта. После тестов чищу через DELETE используя те же идентификаторы которые использовал при создании данных, чтобы оставить окружение чистым для следующего прогона."

Пример

-- Подготовка: создать тестового пользователя
INSERT INTO users (email, password_hash, role, is_active)
VALUES ('playwright_test@example.com', '$2b$10$hashedpassword', 'member', true);

-- Верификация: проверить что существует с правильными значениями
SELECT id, email, role FROM users WHERE email = 'playwright_test@example.com';

-- Очистка: удалить
DELETE FROM users WHERE email = 'playwright_test@example.com';

8. "Как найти все заказы размещённые за последние 7 дней?"

SELECT id, user_id, total, status, created_at
FROM orders
WHERE created_at >= NOW() - INTERVAL '7 days'
ORDER BY created_at DESC;

(Синтаксис немного варьируется по базам данных: PostgreSQL использует INTERVAL '7 days', MySQL использует INTERVAL 7 DAY, SQL Server использует DATEADD(day, -7, GETDATE()))

9. "Что такое подзапрос и когда его использовать?"

Подзапрос: запрос внутри другого запроса.

-- Найти пользователей которые разместили заказы на сумму более 100
SELECT email FROM users
WHERE id IN (
    SELECT user_id FROM orders WHERE total > 100
);

Применение в тестировании: полезен когда нужно фильтровать по условию включающему другую таблицу без JOIN.

10. "Как верифицировать ссылочную целостность после удаления?"

При удалении пользователя нужно проверить что связанные записи также удалены (каскадное удаление) или что внешние ключи предотвратили осиротевшие записи.

-- Подтвердить что пользователь удалён
SELECT COUNT(*) FROM users WHERE id = 123;
-- Ожидается: 0

-- Подтвердить что связанные заказы также удалены (cascade)
SELECT COUNT(*) FROM orders WHERE user_id = 123;
-- Ожидается: 0 (если настроено каскадное удаление)

-- ИЛИ подтвердить что заказы существуют (если используется мягкое удаление)
SELECT id, user_id, deleted_at FROM orders WHERE user_id = 123;
-- Ожидается: строки с выставленным deleted_at

Практические советы для интервью

Если просят написать запрос на доске или в текстовом редакторе

Начни с объяснения что должен делать запрос, потом пиши. Сначала напиши базовую структуру (SELECT ... FROM ... WHERE ...), потом добавляй сложность. Скажи что хотел бы протестировать запрос на реальных данных перед финализацией.

Если не помнишь точный синтаксис

Скажи "я проверил бы документацию для точного синтаксиса, но подход был бы..." и объясни логику. Это намного лучше чем угадывать неверный синтаксис и его защищать.

Если спрашивают о незнакомой базе данных

"Мой опыт в основном с PostgreSQL, но концепция та же в MySQL: синтаксис для работы с датами немного отличается". Осведомлённость о кросс-базовых различиях: плюс.

Быстрый справочник: запросы которые QA-инженеры используют чаще всего

-- Верифицировать что запись создана
SELECT * FROM table WHERE id = 123;

-- Проверить количество (запись создана или удалена)
SELECT COUNT(*) FROM orders WHERE user_id = 456;

-- Найти дубликаты
SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1;

-- Найти осиротевшие записи (не должны существовать)
SELECT o.* FROM orders o
LEFT JOIN users u ON o.user_id = u.id
WHERE u.id IS NULL;

-- Недавние записи
SELECT * FROM logs WHERE created_at > NOW() - INTERVAL '1 hour';

-- Очистить тестовые данные
DELETE FROM users WHERE email LIKE 'test_%';

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

→ See also: SQL для QA: запросы, которые вам действительно нужны | Тестирование баз данных для QA-инженеров: SQL-запросы, которые должен знать каждый тестировщик | Как подготовиться к техническому интервью QA: пошаговое руководство