← Назад к вопросам

Что такое GROUP BY в SQL?

1.3 Junior🔥 292 комментариев
#Базы данных и SQL

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое GROUP BY в SQL?

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

Основная цель и логика работы

Когда вы выполняете запрос с GROUP BY, движок базы данных:

  1. Разделяет все строки из исходной таблицы (или результата JOIN) на группы на основе одинаковых значений в указанных столбцах.
  2. Сворачивает каждую группу в одну результирующую строку.
  3. Позволяет применять агрегатные функции (COUNT, SUM, AVG, MAX, MIN и др.) к другим столбцам в пределах каждой группы.

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

Базовый синтаксис

SELECT 
    column1, 
    column2,
    AGGREGATE_FUNCTION(column3) AS alias
FROM table_name
WHERE условие_фильтрации_строк
GROUP BY column1, column2
HAVING условие_фильтрации_групп
ORDER BY column1;

Ключевые аспекты и правила

  1. Столбцы в SELECT: Все столбцы, перечисленные в SELECT и не являющиеся аргументами агрегатных функций, должны присутствовать в GROUP BY. Это логично, так каждая строка результата описывает конкретную группу, а группа определяется именно этими столбцами.

    -- Правильно: department_id есть в GROUP BY
    SELECT department_id, COUNT(*) AS employee_count
    FROM Employees
    GROUP BY department_id;
    
    -- Ошибка: salary не входит в GROUP BY и не используется в агрегатной функции
    -- SELECT department_id, salary, COUNT(*) ... GROUP BY department_id
    
  2. Агрегатные функции: Именно они придают смысл группировке. Без них GROUP BY во многих СУБД будет работать аналогично DISTINCT для указанных столбцов, но полагаться на это не стоит.

  3. Фильтрация: WHERE vs HAVING:

    * **`WHERE`** — фильтрует **исходные строки** ДО группировки. Не может содержать агрегатных функций.
    * **`HAVING`** — фильтрует **уже сформированные группы** ПОСЛЕ группировки. Может (и обычно должен) содержать агрегатные функции.

```sql
-- Найти отделы с бюджетом на ЗП больше 50000, где у сотрудников з/п > 3000
SELECT 
    department_id, 
    SUM(salary) AS total_salary
FROM Employees
WHERE salary > 3000            -- Сначала отфильтровали высокооплачиваемых
GROUP BY department_id
HAVING SUM(salary) > 50000     -- Затем отфильтровали группы по сумме
ORDER BY total_salary DESC;
```

Практические примеры использования

Пример 1: Анализ отдела

-- Количество сотрудников и средняя зарплата в каждом отделе
SELECT 
    department_id,
    COUNT(*) AS num_employees,
    AVG(salary) AS avg_salary,
    MIN(salary) AS min_salary,
    MAX(salary) AS max_salary,
    SUM(salary) AS total_budget
FROM Employees
WHERE active = 1 -- Только активные сотрудники
GROUP BY department_id;

Пример 2: Анализ продаж за период

-- Ежемесячная выручка по продуктам за текущий год
SELECT 
    product_id,
    EXTRACT(MONTH FROM order_date) AS month,
    SUM(quantity) AS total_units_sold,
    SUM(quantity * unit_price) AS total_revenue
FROM Orders
WHERE EXTRACT(YEAR FROM order_date) = 2024
GROUP BY product_id, EXTRACT(MONTH FROM order_date)
ORDER BY product_id, month;

Особенности и расширенные возможности

  • Группировка по выражению или вычисляемому полю: Можно группировать не только по столбцу, но и по результату выражения.

    -- Группировка по размеру скидки (округленной до 5%)
    SELECT 
        ROUND(discount_percentage / 5) * 5 AS discount_group,
        COUNT(*) AS order_count
    FROM Orders
    GROUP BY ROUND(discount_percentage / 5) * 5;
    
  • Функция GROUPING SETS, ROLLUP, CUBE (расширения SQL): Позволяют создавать несколько уровней агрегации в одном запросе. Например, ROLLUP создает итоги по группам, а также общий итог.

    -- Итоги по отделам + общий итог по компании
    SELECT 
        COALESCE(department_id::TEXT, 'Total Company') AS department,
        SUM(salary) AS total_budget
    FROM Employees
    GROUP BY ROLLUP(department_id);
    
  • Производительность: Для эффективной группировки важны индексы по столбцам, указанным в GROUP BY. Без индексов СУБД может выполнять дорогостоящие операции сортировки или хеширования на больших объемах данных.

Распространенные ошибки

  1. Забыть агрегатную функцию для негруппируемого столбца.
  2. Путать WHERE и HAVING, пытаясь фильтровать группы в WHERE.
  3. Неправильный порядок выполнения: Запрос выполняется как FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY. Понимание этого порядка помогает правильно строить запросы.

Заключение

GROUP BY — это мощный инструмент аналитики и формирования отчетов в SQL. Он лежит в основе большинства запросов для получения сводной информации из детализированных данных. Понимание его работы, правил сочетания с SELECT, а также разницы между WHERE и HAVING является критически важным навыком для любого backend-разработчика, работающего с реляционными базами данных. В современных приложениях GROUP BY часто используется в связке с оконными функциями для выполнения сложных аналитических расчетов без потери детализации строк.