🙏 Спасибо за поддержку проекта. В прошлом месяце мы собрали только $32. Этого хватает на серверы, но не на разработку, поэтому новых уроков и функций в этом месяце не будет. Пожалуйста, поддержите следующий месяц. Поддержать →
SQL код скопирован в буфер обмена

Время чтения: ~7 минут

Группировка данных позволяет превратить набор отдельных строк в категоризованные метрики. GROUP BY — ключевой оператор для отчетов, где нужны итоги по категориям, дням или любым другим признакам. В этом уроке вы разберете синтаксис GROUP BY, главное правило и практические примеры на Sakila. К концу урока вы сможете уверенно строить аналитические запросы с группировкой.

Группировка данных с помощью GROUP BY

В предыдущем уроке вы узнали об агрегатных функциях. Теперь идем дальше: как применять эти функции к разным категориям данных.

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

Синтаксис GROUP BY

Базовая структура:

SELECT column1, AGG_FUNCTION(column2)
FROM table
GROUP BY column1;

Главное правило

Когда используете GROUP BY, каждый столбец в SELECT должен:

  • либо быть в списке GROUP BY;
  • либо быть обёрнут в агрегатную функцию (SUM, COUNT, AVG, MIN, MAX).

Это правило помогает избежать неоднозначности: SQL должен знать, какое значение вернуть для столбца, если в группе несколько строк.

Группировка по одному столбцу

Сумма платежей по каждому клиенту

SELECT customer_id, SUM(amount) AS total_paid
FROM payment
GROUP BY customer_id;

Результат: для каждого клиента одна строка с суммой его платежей.

Количество платежей по сотруднику

SELECT staff_id, COUNT(*) AS payments_count
FROM payment
GROUP BY staff_id;

Результат: для каждого сотрудника показано, сколько платежей он обработал.

Средний платеж по дате

SELECT DATE(payment_date) AS pay_date, AVG(amount) AS avg_payment
FROM payment
GROUP BY DATE(payment_date);

Результат: для каждой даты выводится средний размер платежа.

Вариант: GROUP BY с алиасом

SELECT DATE(payment_date) AS pay_date, AVG(amount) AS avg_payment
FROM payment
GROUP BY pay_date;

Примечание: этот вариант работает в MySQL/MariaDB, но не во всех СУБД. Для кросс-СУБД совместимости лучше писать GROUP BY DATE(payment_date) полностью.


Группировка по нескольким столбцам

Можно группировать по нескольким полям одновременно для более детального анализа.

Сумма платежей по сотруднику и клиенту

SELECT staff_id, customer_id, SUM(amount) AS total_paid
FROM payment
GROUP BY staff_id, customer_id;

Результат: для каждой пары (сотрудник, клиент) выводится сумма платежей.


Практические примеры

Отчет по выручке за каждый день

SELECT DATE(payment_date) AS pay_date, SUM(amount) AS total_sales
FROM payment
GROUP BY DATE(payment_date)
ORDER BY pay_date;

Самые активные клиенты по числу аренд

SELECT customer_id, COUNT(*) AS rentals_count
FROM rental
GROUP BY customer_id
ORDER BY rentals_count DESC;

Среднее количество фильмов по категориям

SELECT category_id, AVG(rental_rate) AS avg_rental_rate
FROM film f
JOIN film_category fc ON f.film_id = fc.film_id
GROUP BY category_id;

Часто задаваемые вопросы

Почему не все столбцы SELECT должны быть в GROUP BY?

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

Можно ли группировать по выражению, а не по столбцу?

Да, например GROUP BY DATE(payment_date) или GROUP BY YEAR(payment_date). Главное — выражение должно быть одинаковым в SELECT и GROUP BY.

Что будет, если GROUP BY пуст?

Это синтаксическая ошибка. GROUP BY всегда должен иметь хотя бы один столбец или выражение.


Вопросы для собеседования

Что такое GROUP BY и зачем оно нужно?

GROUP BY объединяет строки, где выбранные столбцы имеют одинаковые значения, в одну группу. К каждой группе можно применить агрегатные функции для получения сводных показателей.

Почему нельзя выбрать произвольный столбец, если используется GROUP BY?

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

Какая разница между WHERE и HAVING?

WHERE фильтрует строки ДО группировки, а HAVING фильтрует группы ПОСЛЕ группировки. Например, WHERE amount > 10 исключит строки до группировки, а HAVING SUM(amount) > 100 исключит группы с суммой менее 100.


Ключевые выводы этого урока:

  • GROUP BY позволяет разбить данные на группы и применить агрегаты к каждой.
  • Главное правило: все столбцы в SELECT либо в GROUP BY, либо в агрегатной функции.
  • Можно группировать по одному или нескольким столбцам одновременно.
  • Можно группировать по выражениям, например GROUP BY DATE(payment_date).
  • GROUP BY используется для отчетов, аналитики и получения итогов по категориям.

В следующем уроке мы разберем фильтрацию групп с помощью оператора HAVING.

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

  1. Среднее время проката фильма клиентом
  2. Средняя стоимость проката фильма по категории
  3. Покупатели с неотправленными заказами
  4. Анализ стоимости проката фильма по категории