К списку уроков
Блок 6 · Базы данных и SQL

Урок 20. SQL на практике

Запросы, которые нужны тестировщику каждый день

Темы урока

SELECT/FROM/WHERE, ORDER BY/LIMIT/DISTINCT, агрегаты (COUNT/SUM/AVG/MIN/MAX), GROUP BY/HAVING, JOIN (INNER/LEFT/RIGHT), INSERT/UPDATE/DELETE

Видео урока

Пройти тест по уроку

Конспект урока

Главное за урок

SQL — не опциональный скилл для QA. UI может показать «заказ создан», API вернуть 200 — но только SELECT в базе скажет правду: запись появилась, статус сменился, счётчик промокода вырос.

Три кита SQL-запросов для тестировщика: SELECT + WHERE + JOIN. Всё остальное — агрегаты, сортировка, группировка — строится на них.


Структура SQL-запроса

SELECT столбцы        -- что выбираем
FROM таблица          -- откуда
WHERE условие         -- фильтр строк
GROUP BY столбец      -- группировка
HAVING условие        -- фильтр групп
ORDER BY столбец      -- сортировка
LIMIT N;              -- ограничение числа строк

Порядок выполнения отличается от порядка написания: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT.


SELECT и WHERE — базовые запросы

-- Все строки таблицы
SELECT * FROM orders;

-- Конкретные столбцы
SELECT id, email, name FROM users;

-- Фильтрация
SELECT * FROM orders WHERE status = 'paid';
SELECT * FROM users WHERE email LIKE '%@test.ru';
SELECT * FROM products WHERE price BETWEEN 100 AND 500;
SELECT * FROM orders WHERE status IN ('new', 'paid', 'cancelled');
SELECT * FROM orders WHERE user_id IS NOT NULL;

ORDER BY, LIMIT, DISTINCT

-- Сортировка по возрастанию (по умолчанию)
SELECT * FROM orders ORDER BY created_at ASC;

-- Сортировка по убыванию
SELECT * FROM orders ORDER BY total DESC;

-- Первые 10 строк
SELECT * FROM users ORDER BY created_at DESC LIMIT 10;

-- Уникальные значения
SELECT DISTINCT status FROM orders;

Агрегатные функции

Функция Что считает
COUNT(*) Количество строк
SUM(col) Сумма значений
AVG(col) Среднее значение
MIN(col) Минимальное значение
MAX(col) Максимальное значение
SELECT COUNT(*) FROM orders WHERE status = 'paid';
SELECT AVG(total) FROM orders;
SELECT SUM(total) FROM orders WHERE user_id = 1;

GROUP BY и HAVING

-- Количество заказов по статусам
SELECT status, COUNT(*) AS cnt
FROM orders
GROUP BY status
ORDER BY cnt DESC;

-- WHERE фильтрует ДО группировки, HAVING — ПОСЛЕ
SELECT user_id, COUNT(*) AS order_count
FROM orders
GROUP BY user_id
HAVING COUNT(*) > 1;

JOIN — соединение таблиц

Тип Результат
INNER JOIN Только строки с парой в обеих таблицах
LEFT JOIN Все строки левой + совпавшие из правой (или NULL)
RIGHT JOIN Все строки правой + совпавшие из левой (или NULL)
FULL JOIN Все строки обеих таблиц
-- INNER JOIN: заказы с именами пользователей
SELECT o.id, u.name, o.status
FROM orders o
JOIN users u ON o.user_id = u.id;

-- LEFT JOIN: найти заказы без пользователя (нарушение FK)
SELECT o.id, o.user_id
FROM orders o
LEFT JOIN users u ON o.user_id = u.id
WHERE u.id IS NULL;

INSERT, UPDATE, DELETE

-- Создать тестового пользователя
INSERT INTO users (email, name) VALUES ('test@qa.ru', 'Тест QA');

-- Изменить статус заказа
UPDATE orders SET status = 'cancelled' WHERE id = 42;

-- Удалить тестовые данные (всегда сначала SELECT!)
DELETE FROM users WHERE email = 'test@qa.ru';

SQL-кейсы QA: что смотреть в базе

Тест-кейс SQL-запрос
Регистрация SELECT * FROM users WHERE email = 'user@mail.ru'
Оплата SELECT status FROM orders WHERE id = 42
Промокод SELECT used_count, max_uses FROM promo_codes WHERE code = 'QA60'
Нарушение FK SELECT o.id FROM orders o LEFT JOIN users u ON o.user_id = u.id WHERE u.id IS NULL

Ключевые тезисы для теста

  • SELECT * возвращает все столбцы, лучше указывать явно нужные
  • WHERE фильтрует строки до группировки, HAVINGпосле
  • INNER JOIN возвращает только строки с парой в обеих таблицах
  • LEFT JOIN + WHERE right.id IS NULL — паттерн поиска «битых» FK
  • UPDATE без WHERE обновит все строки таблицы — опасно
  • Агрегаты (COUNT, SUM, AVG) нельзя использовать в WHERE, только в HAVING
  • DISTINCT убирает дубликаты из результата
  • SQL нечувствителен к регистру ключевых слов: select = SELECT

Шпаргалка по SQL — все операторы одним экраном

Выборка данных

SELECT *          FROM country;              -- все столбцы
SELECT id, name   FROM country;              -- конкретные столбцы
SELECT name AS city_name FROM city;          -- псевдоним столбца
SELECT co.name, ci.name FROM city AS ci      -- псевдоним таблицы
  JOIN country AS co ON ci.country_id = co.id;

Фильтрация — операторы сравнения

SELECT name FROM city WHERE rating > 3;
SELECT name FROM city WHERE name != 'Berlin' AND name != 'Madrid';

Текстовые операторы

-- Начинается на "P" или заканчивается на "s"
SELECT name FROM city WHERE name LIKE 'P%' OR name LIKE '%s';

-- Любая буква, затем "ublin" (например, Dublin)
SELECT name FROM city WHERE name LIKE '_ublin';

-- Ирландия или Польша (по country_id)
SELECT name FROM city WHERE country_id IN (5, 9);

Другие операторы

-- Население от 500 тыс до 5 млн
SELECT name FROM city WHERE population BETWEEN 500000 AND 5000000;

-- Рейтинг не NULL
SELECT name FROM city WHERE rating IS NOT NULL;

-- Страны с id 1, 4, 7, 8
SELECT name FROM city WHERE country_id IN (1, 4, 7, 8);

Сортировка

SELECT name FROM city ORDER BY rating ASC;   -- по возрастанию
SELECT name FROM city ORDER BY rating DESC;  -- по убыванию

INNER JOIN

Возвращает только строки, у которых есть совпадения в обеих таблицах.

SELECT city.name, country.name
FROM city
[INNER] JOIN country ON city.country_id = country.id;
CITY COUNTRY
Paris 1 1 France
Berlin 2 2 Germany
Warsaw 4

Warsaw не попадает — нет совпадения в country


LEFT JOIN

Возвращает все строки левой таблицы + совпавшие из правой. Если совпадения нет — NULL.

SELECT city.name, country.name
FROM city
LEFT JOIN country ON city.country_id = country.id;
city.name country.name
Paris France
Berlin Germany
Warsaw NULL

RIGHT JOIN

Возвращает все строки правой таблицы + совпавшие из левой. Если совпадения нет — NULL.

SELECT city.name, country.name
FROM city
RIGHT JOIN country ON city.country_id = country.id;
city.name country.name
Paris France
Berlin Germany
NULL Iceland

FULL JOIN

Возвращает все строки обеих таблиц. Где нет совпадения — NULL.

SELECT city.name, country.name
FROM city
FULL [OUTER] JOIN country ON city.country_id = country.id;
city.name country.name
Paris France
Berlin Germany
Warsaw NULL
NULL Iceland

CROSS JOIN

Возвращает все возможные комбинации строк двух таблиц (декартово произведение).

SELECT city.name, country.name
FROM city CROSS JOIN country;

-- Альтернативный синтаксис
SELECT city.name, country.name FROM city, country;

NATURAL JOIN

Объединяет таблицы автоматически по столбцам с одинаковым именем.

SELECT city.name, country.name
FROM city
NATURAL JOIN country;

В примере использовались столбцы country_id, city.name, country.name.
Использовать NATURAL JOIN в реальных проектах не рекомендуется — хрупко при изменении схемы.


Домашнее задание

Выполнить 5 заданий на sql-academy.org + написать SQL с JOIN на «Пиццаеде» в DB Lab. Результат — скриншот + в чат марафона.

Полезные ссылки