Top.Mail.Ru

SQL для тестировщика: что действительно необходимо

В предыдущей статье мы разобрались, что такое базы данных, какие они бывают, базово поняли что такое SQL, зачем он нужен, какие есть базовые команды и для чего они применяются.

А в этой статье - пойдём немного дальше.

Чаще всего тестировщик работает с выборками - то есть с запросами на чтение данных из базы (SELECT). Это позволяет проверить, как система хранит, обрабатывает и отображает информацию.

Команды для изменения данных (INSERT, UPDATE, DELETE) используются в основном, когда нужно подготовить тестовые данные для проверки определенного сценария.

В этой статье мы поговорим о том, что нужно знать тестировщику именно про выборки, чтобы уверенно чувствовать себя в ежедневной работе: какие конструкции используются чаще всего, как составлять запросы с условиями и соединениями, как агрегировать данные и ограничивать выборку, как использовать подзапросы и где потренироваться. Всё - без теории ради теории, только практичные вещи, которые пригодятся в работе.

Напомню, что SQL (Structured Query Language) - это язык, с помощью которого мы "общаемся" с базой данных. Он позволяет:
  • посмотреть, что хранится в таблицах базы данных;
  • добавить новые данные;
  • изменить существующие;
  • удалить лишнее.


SQL - это не абстрактный язык запросов, а реальный инструмент, который помогает делать работу быстрее, точнее и глубже.

А чтобы быстро тренироваться в написании запросов, о которых я буду рассказывать по ходу статьи - вот удобный тренажёр: W3Schools SQL Tutorial - можно ввести запрос и сразу увидеть результат!

Компания Software Cats уже более пяти лет занимается аутстафом и аутсорсом по направлениям

Если у вас есть ИТ-проблема, оставьте ваши контакты, и мы поможем составить план ее решения.

Минимальный набор SQL-команд, которые действительно используются в работе тестировщика

Чтобы эффективно работать с базой данных, тестировщику не нужно знать весь SQL,  достаточно уверенно пользоваться небольшим, но мощным набором команд. Вот основные из них:

SELECT

SELECT - выбрать, дословно с английского - “выбрать”.

Самая частая команда, которую ты будешь использовать. Позволяет получить данные из таблицы.

SELECT - запросы строятся по понятной логике: какие данные хотим получить, откуда конкретно их брать.

Например: “Покажи (данные) email’ы всех пользователей из (откуда) таблицы пользователей”

На языке SQL это будет выглядеть так:
SELECT email 
FROM users;
Читается почти как обычное предложение!

WHERE

WHERE - условие выборки, дословно с английского - “где”.

WHERE - используем, когда надо уточнить что именно нам нужно (а это почти всегда!).

Пример:

“Покажи всех пользователей старше 30 лет”:
SELECT * 
FROM users 
WHERE age > 30;
* - означает все данные из таблицы.

В условиях можно использовать:
= равно,
> / < больше / меньше,
>=, <= больше/меньше или равно,
!= или <> не равно,
AND, OR для того, чтобы комбинировать условия.

Например:
SELECT * 
FROM users 
WHERE age > 30 
AND status = 'active';
Запросы с WHERE - это уже 80% успешной работы с SELECT!

ORDER BY

ORDER BY - порядок сортировки данных в выборке, дословно с английского - “упорядочить по”.

Если нужно не просто получить данные, а вывести их в определённом порядке - используется ORDER BY.

По умолчанию (без ORDER BY)  данные выводятся в том порядке, как они есть в таблице - иногда это мешает анализу. ORDER BY помогает навести порядок.

Пример:

“Покажи пользователей по возрасту - от младших к старшим”:
SELECT * 
FROM users 
ORDER BY age;
При этом данные можно вывести:

ASC - по возрастанию (по умолчанию, можно не писать),
DESC - по убыванию.

Можно сортировать сразу по нескольким полям:
SELECT * 
FROM users 
ORDER BY status, age DESC;
Сначала сортируем по статусу, потом по возрасту в обратном порядке внутри каждой группы.

А вот парочка скринов, как это выглядит в реальной базе данных.
SELECT * 
FROM users;
SELECT * 
FROM users 
WHERE role=’ADMIN’;

LIMIT

LIMIT - ограничить количество выдаваемых результатов, дословно с английсчкого “предел”.

LIMIT - ограничивает количество строк в выдаче. Иногда в таблице слишком много данных, а нам нужно посмотреть только первые несколько строк. В таких случаях используется LIMIT.

Например: “Покажи только 10 пользователей”:
SELECT * 
FROM users 
LIMIT 10;
Можно комбинировать с ORDER BY, чтобы получить, например, только последние заказы:
SELECT * 
FROM orders 
ORDER BY created_at DESC LIMIT 5;
Сначала сортируем по дате (от новых к старым), потом берём только первые 5 строк.

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

Иногда нужно не просто посмотреть строки, а посчитать их, найти максимальное, среднее или сумму. Для этого используются агрегатные функции:

COUNT(*) - посчитать количество строк,
MAX() - максимальное значение,
MIN() - минимальное значение,
AVG() - среднее,
SUM() - сумма.

Примеры:

“Сколько всего пользователей в таблице?”:
SELECT COUNT(*) 
FROM users;
“Какой максимальный возраст среди пользователей?”:
SELECT MAX(age)
FROM users;
“Какой средний возраст у активных пользователей?”:
SELECT AVG(age) 
FROM users 
WHERE status = 'active';
Агрегатные функции возвращают одно значение вместо списка строк и часто используются для быстрой оценки ситуации в базе.

GROUP BY

GROUP BY - группирует данные по какому-то признаку, дословно с английского -“группировать”.

Если агрегатные функции (COUNT, MAX, AVG и т.д.) считают всё в целом, то GROUP BY позволяет разбить данные на группы и посчитать что-то внутри каждой группы отдельно.

Например:

“Сколько пользователей в каждом статусе?”:
SELECT status, COUNT(*) 
FROM users 
GROUP BY status;
Этот запрос разобьёт всех пользователей по статусу и покажет, сколько в каждой группе.

“Какой средний возраст пользователей в каждой роли?”:
SELECT role, AVG(age) 
FROM users 
GROUP BY role;
Этот запрос разобьет всех пользователей по ролям и посчитает средний возраст пользователя в каждой роли.

GROUP BY - мощный инструмент, особенно когда нужно анализировать данные по категориям.

Главное правило использования GROUP BY: если используешь GROUP BY, в SELECT должны быть только поля из GROUP BY или агрегатные функции.

Например:
SELECT id, status, COUNT(*) 
FROM users 
GROUP BY status;
В SELECT указано поле, которое не участвует в GROUP BY и не обернуто в агрегатную функцию, будет ошибка - такой запрос “упадет” и не выдаст никаких результатов.

HAVING

HAVING - это тоже условие выборки, как и WHERE, дословно с английского - “имея”, но только в том случае, если используется GROUP BY.

Иногда после группировки нужно оставить только те группы, которые соответствуют какому-то условию.

Например:

“Показать только те роли, где больше 5 пользователей.”:
SELECT role, COUNT(*) 
FROM users 
GROUP BY role 
HAVING COUNT(*) > 5;
В этом случае используется HAVING (а не WHERE, потому что WHERE работает до группировки).

JOIN - как соединять таблицы

JOIN - объединяет данные из нескольких таблиц, дословно с английского - “присоединение”.

В большинстве реальных проектов данные не лежат в одной таблице. Пользователи - в одной, заказы - в другой, оплаты - в третьей. Чтобы получить осмысленную информацию, таблицы нужно соединять - и для этого используется JOIN.

Приведу пример: представим, что у нас есть две таблицы В таблице users (пользователи) хранятся имена пользователей, а в таблице orders (заказы), соответственно - заказы этих пользователей.
users

id

name

1

Иван

2

Мария

оrders

id

user_id

amount

1

1

500

2

2

700

3

1

250

Хочешь узнать, кто сделал какой заказ? Тогда для начала давай вспомним про первичный ключ (Primary Key) и внешний ключ (Foreign Key) из статьи “Что тестировщику нужно знать о базах данных”.

В реляционных базах важно не только хранить данные, но и правильно связывать их между собой. Например, заказ должен быть привязан к конкретному покупателю. Для этого используются:

  • Первичный ключ (Primary Key) - уникальный идентификатор записи в таблице. Например, в таблице заказов это поле id.
  • Внешний ключ (Foreign Key) - ссылка на запись в другой таблице, обеспечивает связь между таблицами. Например, в таблице заказов поле user_id указывает на конкретного клиента в таблице users (на первичный ключ этой таблицы - id).

Чтобы соединить таблицы users и orders, нужно явно указать условие, по которому строки из одной таблицы соответствуют строкам из другой. Это делается с использованием ключей и с помощью конструкции JOIN ... ON.

Например:
SELECT users.name, orders.amount
FROM users
JOIN orders ON users.id = orders.user_id;
Результат будет такой:

name

amount

Иван

500

Мария

700

Иван

250

Давайте разбираться, что здесь происходит.

  1. Мы берём таблицу users как основную;
  2. JOIN-им (присоединяем) к ней таблицу orders;
  3. Задаем условие соединения: users.id = orders.user_id (то есть id пользователя = id пользователя в таблице заказов);
  4. В результат попадут только те строки, где совпадение есть.

Такой JOIN по умолчанию называется INNER JOIN - он возвращает только те строки, у которых есть соответствие в обеих таблицах.
Виды JOIN - какие бывают и когда использовать
Чтобы понять, как именно работает соединение, важно знать основные типы JOIN.
INNER JOIN (внутреннее соединение)
Показывает только те записи, у которых есть совпадения в обеих таблицах.

По умолчанию объединение является внутренним т.е. JOIN и INNER JOIN дадут один и тот же результат.
SELECT users.name, orders.amount 
FROM users 
INNER JOIN orders 
ON users.id = orders.user_id;
Если у пользователя нет заказов - он не попадет в результат.
FULL OUTER JOIN (внешнее соединение) = FULL JOIN
Внешнее соединение может быть трех типов: левое (LEFT), правое (RIGHT) и полное (FULL). По умолчанию оно является полным.

Главным отличием внешнего соединения от внутреннего является то, что оно обязательно возвращает все строки одной (LEFT, RIGHT) или двух таблиц (FULL).
SELECT users.name, orders.amount 
FROM users 
FULL JOIN orders 
ON users.id = orders.user_id;
LEFT JOIN (левое соединение) = LEFT OUTER JOIN
Возвращает все строки из левой таблицы (той, что указана первой) и совпадающие им из правой. Если совпадающих записей в правой таблице нет - значения из неё будут NULL.
SELECT users.name, orders.amount 
FROM users 
LEFT JOIN orders 
ON users.id = orders.user_id;
Полезно, когда нужно найти, например, пользователей без заказов.

Применяя условие WHERE orders.user_id IS NOT NULL можно выбрать только те значения из левой таблицы, у которых нет совпадений с правой.
RIGHT JOIN (правое соединение) = RIGHT OUTER JOIN
Работает зеркально LEFT JOIN и он возвращает все строки из правой таблицы и совпадающие значения из левой. Если совпадений нет - значения из левой таблицы будут NULL.
SELECT users.name, orders.amount 
FROM users 
RIGHT JOIN orders 
ON users.id = orders.user_id;
Точно так же, как и для LEFT JOIN применяя условие WHERE orders.user_id IS NOT NULL можно выбрать только те значения из правой таблицы, у которых нет совпадений с левой.
SELF JOIN (самосоединение)
Используется, когда нужно сравнить строки внутри одной и той же таблицы. Например, если имеется иерархическая структура данных.

Представим, что в таблице employees хранятся сотрудники и их руководители. Поле manager_id ссылается на эту же таблицу. Чтобы получить имя начальника, нужно соединить таблицу с самой собой.
SELECT e.name AS employee, m.name AS manager 
FROM employees e 
LEFT JOIN employees m 
ON e.manager_id = m.id;
Ключевое слово AS используется, чтобы дать понятное имя столбцу или таблице прямо в запросе. SELECT name AS user_name FROM users;

Так мы говорим: “отобразить колонку name под именем user_name”.
Понимание различных видов JOIN - один из главных шагов к уверенной работе с SQL.

JOIN помогает «собрать» данные из разных таблиц в осмысленную картину: кто что сделал, когда, сколько потратил, с кем связан и т.д.

Хорошая новость: достаточно понять логику и немного потренироваться и JOIN больше не будет пугать, а станет привычным и удобным инструментом.

Подзапросы - запрос в запросе

Иногда нужно сначала что-то найти, а потом использовать результат внутри другого запроса. Для этого и нужны подзапросы - они позволяют вложить один запрос внутрь другого.

Это как “промежуточный расчёт”, который делает SQL сам внутри основного запроса.

Например, найти пользователей, у которых сумма покупок выше средней:
SELECT name FROM customers
WHERE total_spent > (
  SELECT AVG(total_spent) FROM customers
);
Подзапросы можно писать в разных частях основного запроса:

Где используется

Пример

В WHERE

WHERE age > (SELECT AVG(age)...)

В FROM (как таблица)

FROM (SELECT ...)

В SELECT

SELECT (SELECT COUNT(*) ...)

Подзапросы делают SQL гибким и читаемым - особенно когда сложно сформулировать всё в одной строке. Не надо их бояться: если мысленно выбираешь “сначала это, потом то” - подзапрос тебе подойдет.

Упражнение

А теперь, давайте выполним и разберем небольшое упражнение, чтобы закрепить знания и понять как шаг за шагом можно создавать сложные запросы.

Допустим, для отчета нам нужно узнать средний возраст покупателей, которые купили три самых дорогих товара за последний месяц.
Таблица customers

customer_id

name

age

1

Иван

34

2

Мария

28

3

Ирина

41

4

Игорь

25

Таблица orders

order_id

customer_id

product_id

order_date

1001

1

101

2025-08-03

1002

2

102

2025-08-01

1003

3

105

2025-08-05

1004

1

103

2025-07-30

1005

4

104

2025-08-04

1006

2

103

2025-08-04

Таблица products

product_id

name

price

101

Смартфон

70000

102

Ноутбук

120000

103

Наушники

15000

104

Умные часы

25000

105

Граф. планшет

90000

Давайте разберем по порядку:

Шаг 1. Надо узнать какие 3 товара самые дорогие. Получаем три самых дорогих товаров - SELECT product_id, name, price. Результаты нужно отсортировать по цене по убыванию ORDER BY products.price DESC и взять только 3 первых результата - LIMIT 3.

Для дальнейшей работы нам понадобится ключ - product_id.
SELECT product_id, name, price
FROM products
ORDER BY price DESC
LIMIT 3;
Результат: 3 самых дорогих товара

product_id

name

price

102

Ноутбук

120000

105

Граф. планшет

90000

101

Смартфон

70000

Шаг 2. Найти всех, кто заказывал эти товары за последний месяц
Из предыдущего запроса мы выяснили, что самые дорогие товары - это product_id 102, 105, 101.

Теперь нужно найти все заказы, сделанные на эти товары в течение последнего месяца.

Для этого используем таблицу orders и фильтрацию по дате и product_id:
SELECT *
FROM orders
WHERE product_id IN (102, 105, 101)
AND order_date >= CURRENT_DATE - INTERVAL '1 month';
Ключевое слово IN используется, когда в условии нужно выбрать несколько значений.

А поскольку мы уже знаем каким запросом можно получить product_id самых дорогих товаров, то можем использовать подзапрос.
SELECT *
FROM orders
WHERE product_id IN (
    SELECT product_id
    FROM products
    ORDER BY price DESC
    LIMIT 3
)
AND order_date >= CURRENT_DATE - INTERVAL '1 month';
Здесь CURRENT_DATE - INTERVAL - это универсальный способ задавать динамические временные диапазоны в SQL. Вместо фиксированных дат, мы указываем относительное время. Такой подход полезен, когда нужно проверять данные за последний период, и важно, чтобы запрос работал корректно в любой день.

Можно указывать и другие интервалы: '7 days', '2 years', '10 minutes' - всё читается буквально как обычное предложение!
Результат: заказы за последний месяц (август) на три самых дорогих товара.

order_id

customer_id

product_id

order_date

1001

1

101

2025-08-03

1002

2

102

2025-08-01

1003

3

105

2025-08-05

Шаг 3. Теперь нам нужно понять, кто именно делал эти заказы и посчитать средний возраст этих покупателей.
Возьмем данные из таблицы таблицы orders и добавим к ним данные из customers используя JOIN
SELECT *
FROM orders
JOIN customers ON orders.customer_id = customers.customer_id
WHERE product_id IN (
    SELECT product_id
    FROM products
    ORDER BY price DESC
    LIMIT 3
)
AND order_date >= CURRENT_DATE - INTERVAL '1 month';
Результат выполнения запроса

order_id

customer_id

product_id

order_date

name

age

1001

1

101

2025-08-03

Иван

34

1002

2

102

2025-08-01

Мария

28

1003

3

105

2025-08-05

Ирина

41

Теперь применим агрегатную функцию  AVG().
SELECT AVG(customers.age) 
FROM orders
JOIN customers ON orders.customer_id = customers.customer_id
WHERE product_id IN (
    SELECT product_id
    FROM products
    ORDER BY price DESC
    LIMIT 3
)
AND order_date >= CURRENT_DATE - INTERVAL '1 month';
Результатом выполнения этого запроса будет одно число: (34+28+4)/3 = 34.33.

Итак, в этой статье мы разобрали ключевые конструкции SQL, которые действительно нужны тестировщику: от простых выборок SELECT до сложных соединений JOIN и подзапросов. Это базовый, но очень мощный набор инструментов, который поможет не только получать нужные данные, но и понимать, как они устроены в системе.

Освоив эти основы, ты сможешь:

  • уверенно читать и писать SQL-запросы,
  • не бояться работать с базой данных,
  • быстрее находить причины багов,
  • строить собственную аналитику для тестирования.

Но это - только начало. SQL гораздо шире и глубже. Есть оконные функции, транзакции, триггеры, индексы и многое другое. Если почувствуешь, что хочешь копнуть глубже - в Интернете доступно множество обучающих материалов и тренажеров, главное - немного тренировки и все получится!

Наша команда уже более пяти лет занимается реализацией проектов на Java и усилением команд по направлениям

За время существования компании, мы принимали участие в работе над более чем 100 проектами различного объема и длительности.

Если перед вами стоят вызовы, при которых вам может пригодится наша экспертиза, просто напишите нам,

Мы договоримся с вами об онлайн-встрече, чтобы подробнее обсудить ваш проект и вашу проблему.
Руководитель отдела тестирования Software Cats

Еще почитать по теме:

    Обсудить проект _
    Если у вас есть ИТ-проблема , оставьте свои контакты, и мы поможем правительству спланировать ее решение . Обещаем не рассылать спам.
    hello@softwarecats.dev
    Новосибирск, ул. Демакова
    23/5, оф.308
    Контакты _

    Выполненные проекты: