SQL для QA інженера: що реально потрібно знати
SQL — один з найбільш недооцінених скілів для QA початківців. Але коли ви вперше зможете самостійно перевірити що дані правильно збереглись в БД після тесту — це змінить підхід до тестування.
Ця стаття — практичний мінімум. Без академічних визначень, з реальними прикладами з QA роботи.
Навіщо QA знати SQL
Верифікація даних. UI показує "замовлення збережено" — але чи правильні дані в базі? Тільки SQL-запит дасть точну відповідь.
Підготовка тест-даних. Потрібно протестити обробку замовлень "старших 30 днів" — простіше вставити тестові дані через SQL ніж створювати їх через UI.
Дебаг багів. "Баг не репродукується" — перевіряємо стан даних в БД і знаходимо причину.
Тестування без UI. Перевірити що бекграунд-процес правильно обробив записи — тільки через БД.
Основи SELECT
-- Отримати всі записи з таблиці
SELECT * FROM users;
-- Отримати конкретні поля
SELECT id, name, email FROM users;
-- З умовою
SELECT * FROM users WHERE email = 'test@example.com';
-- Кілька умов
SELECT * FROM users WHERE role = 'admin' AND is_active = true;
SELECT * FROM orders WHERE status = 'pending' OR status = 'processing';WHERE: умови відбору
-- Рівність і нерівність
WHERE age = 25
WHERE age != 25 -- або <> 25
WHERE age > 18
WHERE age >= 18
WHERE age BETWEEN 18 AND 65
-- Рядки
WHERE name = 'Іван'
WHERE email LIKE '%@gmail.com' -- закінчується на @gmail.com
WHERE name LIKE 'Ів%' -- починається з "Ів"
WHERE name ILIKE '%іван%' -- case-insensitive пошук (PostgreSQL)
-- NULL перевірка
WHERE deleted_at IS NULL -- активні записи
WHERE deleted_at IS NOT NULL -- видалені записи
-- Список значень
WHERE status IN ('pending', 'processing', 'shipped')
WHERE id NOT IN (1, 2, 3)
-- Дати
WHERE created_at >= '2026-01-01'
WHERE created_at BETWEEN '2026-01-01' AND '2026-12-31'
WHERE created_at >= NOW() - INTERVAL '7 days' -- за останні 7 днівРеальні QA приклади
Перевірити що user зареєструвався
-- Після реєстрації через UI або API:
SELECT id, name, email, created_at, is_verified
FROM users
WHERE email = 'test@example.com';
-- Що перевіряємо:
-- ✅ Запис існує
-- ✅ name і email відповідають введеним даним
-- ✅ created_at = сьогодні
-- ✅ is_verified = false (якщо потрібна верифікація email)Перевірити що замовлення створилось
SELECT
o.id,
o.status,
o.total_amount,
o.created_at,
o.user_id
FROM orders o
WHERE o.user_id = 123
ORDER BY o.created_at DESC
LIMIT 1;
-- Перевіряємо найновіше замовлення цього userПеревірити що пароль змінився (без бачення самого пароля)
-- Запам'ятовуємо хеш ДО зміни
SELECT password_hash FROM users WHERE id = 456;
-- '...старий_хеш...'
-- Змінюємо пароль через UI
-- Перевіряємо що хеш змінився
SELECT password_hash FROM users WHERE id = 456;
-- '...новий_хеш...' (повинен відрізнятись)ORDER BY і LIMIT
-- Сортування за датою (нові спочатку)
SELECT * FROM orders ORDER BY created_at DESC;
-- Перші 10 записів
SELECT * FROM users ORDER BY created_at DESC LIMIT 10;
-- Сторінка 2 з 10 записів (пагінація)
SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 10;
-- Знайти останнє замовлення конкретного user
SELECT * FROM orders
WHERE user_id = 123
ORDER BY created_at DESC
LIMIT 1;COUNT, SUM, AVG: агрегатні функції
-- Кількість users
SELECT COUNT(*) FROM users;
-- Кількість активних users
SELECT COUNT(*) FROM users WHERE is_active = true;
-- Загальна сума замовлень
SELECT SUM(total_amount) FROM orders WHERE status = 'completed';
-- Середній чек
SELECT AVG(total_amount) FROM orders WHERE status = 'completed';
-- Кількість замовлень по статусам
SELECT status, COUNT(*) as count
FROM orders
GROUP BY status;
-- Результат:
-- pending | 45
-- processing | 12
-- completed | 234
-- cancelled | 8JOIN: об'єднання таблиць
Найважливіша тема для QA. Реальні дані зберігаються в кількох таблицях.
INNER JOIN — тільки ті що є в обох таблицях
-- Замовлення з іменами users
SELECT
o.id as order_id,
o.total_amount,
o.status,
u.name as user_name,
u.email
FROM orders o
INNER JOIN users u ON o.user_id = u.id
WHERE o.status = 'pending';LEFT JOIN — всі з лівої таблиці + відповідні з правої
-- Всі users і кількість їх замовлень (включно з тими хто не замовляв)
SELECT
u.id,
u.name,
u.email,
COUNT(o.id) as orders_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name, u.email
ORDER BY orders_count DESC;Реальний QA приклад: перевірити що order_items правильні
-- Після створення замовлення з 2 товарами
SELECT
o.id as order_id,
o.total_amount,
oi.product_id,
oi.quantity,
oi.price,
p.name as product_name
FROM orders o
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
WHERE o.id = 789;
-- Перевіряємо:
-- ✅ Є 2 рядки (2 товари)
-- ✅ Quantity і price відповідають тому що вибрали
-- ✅ total_amount = SUM(oi.quantity * oi.price)Перевірка цілісності даних
-- Orphan records: order_items без orders (баг!)
SELECT oi.*
FROM order_items oi
LEFT JOIN orders o ON oi.order_id = o.id
WHERE o.id IS NULL;
-- Users з дублікатами email (якщо такого не повинно бути)
SELECT email, COUNT(*) as count
FROM users
GROUP BY email
HAVING COUNT(*) > 1;
-- Замовлення з нульовою сумою (підозріло)
SELECT * FROM orders
WHERE total_amount = 0 OR total_amount IS NULL;
-- Рядки в невалідному статусі
SELECT * FROM orders
WHERE status NOT IN ('pending', 'processing', 'shipped', 'completed', 'cancelled');Підготовка тест-даних
-- Вставка тестового user
INSERT INTO users (name, email, role, created_at)
VALUES ('Test User', 'testqa@example.com', 'user', NOW());
-- Масова вставка тестових даних
INSERT INTO products (name, price, category) VALUES
('Тестовий продукт 1', 100.00, 'electronics'),
('Тестовий продукт 2', 250.00, 'electronics'),
('Тестовий продукт 3', 50.00, 'books');
-- Оновлення для тесту (наприклад, зробити замовлення "старим")
UPDATE orders
SET created_at = NOW() - INTERVAL '35 days'
WHERE id = 789;
-- Видалення тестових даних після тесту
DELETE FROM users WHERE email LIKE '%testqa%';⚠️ Завжди робіть INSERT/UPDATE/DELETE тільки в тестовій БД! Перед виконанням перевірте до якої бази підключені.
Транзакції: коли тестуєте критичні операції
-- Починаємо транзакцію (зміни не застосовуються одразу)
BEGIN;
-- Робимо тестові зміни
UPDATE orders SET status = 'cancelled' WHERE id = 789;
-- Перевіряємо результат
SELECT * FROM orders WHERE id = 789;
-- Якщо все ок — застосовуємо
COMMIT;
-- Або скасовуємо якщо щось не так
ROLLBACK;Практичний чеклист SQL для QA
Базовий рівень (Junior):
□ SELECT з WHERE і кількома умовами
□ ORDER BY і LIMIT
□ COUNT записів
□ Перевірка NULL значень
Середній рівень (Middle):
□ JOIN двох таблиць (INNER і LEFT)
□ GROUP BY з COUNT/SUM
□ Пошук дублікатів
□ Дати і часові відрізки
Практика:
□ Верифікація даних після кожного API тесту
□ Пошук orphan records
□ Перевірка цілісності після batch операцій
Де практикуватись
SQLZoo (sqlzoo.net) — інтерактивні завдання в браузері, безкоштовно.
LeetCode SQL — задачі від простих до складних.
pgexercises.com — PostgreSQL-специфічні вправи.
Реальна практика: попросіть доступ до тестової БД на роботі або встановіть PostgreSQL локально і практикуйтесь на реальних даних.
Підсумок
Для QA не потрібно знати весь SQL на рівні DBA. Потрібно впевнено писати SELECT запити з умовами, JOIN і базовою агрегацією — і це вже відкриє можливість тестувати на рівні даних, а не тільки UI.
Почніть з SELECT і WHERE, за тиждень практики додайте JOIN — і ви вже будете в топ 30% QA за цим скілом.