Перейти к основному содержимому

SQL для тестировщика

Тестировщику Аналитику

Зачем эта статья. UI показал «Заказ создан», API вернул 200 — а в базе запись есть? Баланс списался? Статус верный? Без SQL вы верите интерфейсу на слово. Здесь — минимум запросов для ежедневной работы QA; углубление — в разделе SQL.

:::warning Только тестовые стенды Запросы выполняйте на test / staging, с read-only учёткой, если возможно. Не правьте продакшен «просто проверить». Согласуйте доступ с DBA или разработчиком. :::


База данных простыми словами

База данных (БД) — хранилище структурированных данных приложения. Для QA важнее всего реляционная модель:

ПонятиеАналогияПример
ТаблицаЛист Excelusers, orders
Строка (row)Одна записьодин пользователь, один заказ
Столбец (column)Полеemail, status, total_amount
Первичный ключ (PK)Уникальный id строкиusers.id = 42
Внешний ключ (FK)Ссылка на другую таблицуorders.user_idusers.id

SQL (Structured Query Language) — язык запросов к таким таблицам. Тестировщику чаще всего нужен только SELECT — чтение без изменения данных.


Словарь команд (что увидите в запросах)

Команда / словоЧто делает
SELECT«Верни столбцы…»
FROM«…из таблицы…»
WHERE«…где условие»
JOIN«Соедини две таблицы по связи»
ORDER BYСортировка
LIMITВзять только N строк
COUNT, SUMПосчитать строки или сумму
GROUP BYГруппировка (например, по дню)
HAVINGФильтр после группировки
NULL«Значения нет» (не ноль и не пустая строка)

INSERT, UPDATE, DELETE на проде — только по согласованию. На тесте иногда чистят данные скриптами разработчиков.


Что должен уметь тестировщик

НавыкЗачем
SELECT + WHEREНайти запись пользователя, заказа, платежа
JOINСвязать заказ с пользователем и товарами
COUNT, SUMСверить количество строк с UI
ORDER BY + LIMITПоследние N операций
Понимание транзакцийПочему «деньги списались, заказ не создался»

Полный курс SQL — необязателен для старта в QA. Достаточно 10–15 шаблонов ниже.

Транзакция — одним абзацем

Транзакция — набор операций в БД «всё или ничего». Пример: списать деньги и создать заказ. Если второй шаг упал, откат возвращает баланс. В баг-репорте полезно спросить: «операция в одной транзакции?» — объясняет «половинчатые» состояния.


Как подключиться

ИнструментКогда
DBeaver, DataGrip, pgAdminРучные проверки, экспорт в CSV
Консоль psql, mysqlБыстрый запрос с сервера
Запрос из автотестаИнтеграционное тестирование

Уточните у команды: СУБД (PostgreSQL, MySQL, MS SQL), имя схемы, тестовая база, логин только на чтение.


Схема «UI сказал X — SQL подтвердил»

Частый рабочий цикл QA:

  1. Выполнить действие в UI или через API (создать заказ, сменить статус).
  2. Зафиксировать факт в интерфейсе: «Заказ №1001 — Оплачен».
  3. Выполнить SQL на том же тестовом стенде и сравнить с оракулом из требований.
-- После оплаты в UI ожидаем status = 'paid' и одну запись
SELECT id, status, total_amount, paid_at
FROM orders
WHERE id = 1001;
Что сравниваемUI / APISQL
Статус«Оплачен»status = 'paid'
Сумма1 990 ₽total_amount = 1990.00
Количество в списке«3 заказа»COUNT(*) ... = 3

Если UI и БД расходятся — это дефект целостности данных (часто серьёзнее «кривой вёрстки»). В баг-репорт кладут оба факта: скрин UI и результат запроса.


10 запросов, которые покрывают 80% задач

1. Найти пользователя по email

SELECT id, email, status, created_at
FROM users
WHERE email = 'qa@test.local';

После регистрации через UI — проверка, что строка появилась. Пустой результат → запись не создалась или другой стенд/база.

2. Последние заказы пользователя

SELECT id, user_id, total_amount, status, created_at
FROM orders
WHERE user_id = 42
ORDER BY created_at DESC
LIMIT 10;

ORDER BY ... DESC — сначала новые; LIMIT 10 — не выгружать миллион строк.

3. Заказ со строками (JOIN)

Две таблицы: заказ и позиции. JOIN соединяет строки, где order_items.order_id = orders.id.

SELECT o.id AS order_id, o.status, oi.product_id, oi.quantity, oi.price
FROM orders o
JOIN order_items oi ON oi.order_id = o.id
WHERE o.id = 1001;

Сверьте: сумма quantity * price по строкам = итог в UI (с учётом скидок по ТЗ).

LEFT JOIN (в запросе 9) — «все заказы, даже если пользователь пропал»; где связи нет, справа будет NULL.

4. Количество записей

SELECT COUNT(*) FROM orders WHERE status = 'pending';

Сравните с фильтром «Ожидают оплаты» в админке. Расхождение на 1 — уже повод для бага.

5. Дубликаты (anomaly hunting)

SELECT email, COUNT(*) AS cnt
FROM users
GROUP BY email
HAVING COUNT(*) > 1;

GROUP BY — сгруппировать по email; HAVING — оставить только группы, где больше одной строки.

6. «Зависшие» статусы

SELECT id, status, updated_at
FROM payments
WHERE status = 'processing'
AND updated_at < NOW() - INTERVAL '1 hour';

Синтаксис интервала зависит от СУБД (INTERVAL в PostgreSQL; в SQL Server — DATEADD). Уточните у разработчика.

7. Сумма по периоду

SELECT DATE(created_at) AS day, SUM(total_amount) AS revenue
FROM orders
WHERE created_at >= '2026-03-01'
GROUP BY DATE(created_at)
ORDER BY day;

Сверка с отчётом аналитики или экспортом.

8. Мягкое удаление (soft delete)

SELECT id, deleted_at
FROM products
WHERE id = 55 AND deleted_at IS NOT NULL;

После «удаления» в UI товар часто остаётся в БД с меткой deleted_at — это норма по ТЗ, а не «баг удаления».

9. Проверка связи FK

SELECT o.id
FROM orders o
LEFT JOIN users u ON u.id = o.user_id
WHERE u.id IS NULL;

Результат должен быть пустым. Иначе — заказы без пользователя (битая миграция или баг API).

10. Аудит после тестового прогона

SELECT *
FROM audit_log
WHERE entity_type = 'order' AND entity_id = 1001
ORDER BY created_at;

Кто и когда менял статус — доказательная база для баг-репорта.


Полный пример расследования бага

Симптом: в UI «Оплата не прошла», деньги «списались» (со слов пользователя).

ШагДействие
1В Network: POST /api/pay → 500, тело {"code":"PAYMENT_GATEWAY_TIMEOUT"}
2Запомнить order_id=1001, время 14:32
3SQL: SELECT * FROM payments WHERE order_id = 1001 ORDER BY created_at DESC LIMIT 5;
4Видим: последняя запись status='processing', списание в wallet_transactions есть
5Баг: «при 500 от шлюза платёж остаётся processing, UI показывает общую ошибку» + скрин + JSON + SELECT

Связка UI → API → SQL

  1. Воспроизвести в браузере, сохранить Request ID / время.
  2. В Network — URL, тело запроса, ответ.
  3. В SQL — найти payment_id или order_id по времени и user_id.
  4. В баг-репорт — шаги UI + фрагмент JSON + результат SELECT.

Типичные ошибки новичка

ОшибкаКак избежать
Смотрят прод вместо testСверить hostname и имя БД в клиенте
SELECT * на огромной таблицеУказывать столбцы и LIMIT
Сравнивают UI с устаревшей строкойСортировка ORDER BY created_at DESC
Путают NULL и 0WHERE deleted_at IS NULL — отдельный смысл
Один запрос без JOINПозиции заказа смотрят в orders, а не в order_items

Тестовые данные

ПравилоПочему
Не копировать прод без маскировкиGDPR, 152-ФЗ
Префикс qa_, test_Легко найти и удалить
Скрипты seed от разработчиковВоспроизводимое окружение
Откат после интеграционных тестов121 — практикум

Подробнее — Документация тестировщика.


Куда углубляться

ТемаРаздел
Основы SELECT, WHERE, JOINSQL — введение
Шпаргалка типовых задач885 — шпаргалка SQL
Тестирование БД в автотестах118 — тестирование баз данных
API + проверка ответаТестирование API
Ручная проверка UI перед SQLРучное тестирование веба

См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).