Правило GROUP BY для столбцов SELECT
Узнайте, почему каждый неагрегированный столбец должен присутствовать в GROUP BY, и разберитесь с режимом only-full-group-by.
«Правило GROUP BY для столбцов SELECT» — бесплатный урок Coding Interview Prep на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Coding Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Coding Interview Prep содержит 4 уроков всего.
Почему на собеседованиях начинают с GROUP BY
Именно GROUP BY часто отделяет на собеседованиях начинающих специалистов от специалистов среднего уровня. Главное правило, которое проверяют чаще всего: каждый столбец в списке SELECT должен находиться внутри агрегатной функции или быть указан в GROUP BY.
Если нарушить это правило, движок не сможет определить, какое значение показать для группы, содержащей несколько строк. Интервьюеры намеренно создают такую ошибку, чтобы проверить, понимаете ли Вы, что на самом деле представляет собой группа.
Что такое группа на самом деле
GROUP BY сворачивает множество строк в одну строку для каждого уникального ключа. После группировки движок больше не располагает отдельными строками. У него остаётся только одна итоговая строка на группу.
- У столбцов, по которым выполнена группировка, есть одно однозначное значение для каждой группы.
- Агрегаты вроде
COUNT,SUM,AVGсводят множество значений к одному. - Любой другой необработанный столбец неоднозначен: какое из множества значений следует вывести?
SELECT department, COUNT(*) AS headcount
FROM employees
GROUP BY department;Классическая ошибка
Вот ошибка, которую особенно любят интервьюеры. Вы выполняете группировку по department, но одновременно выбираете name — неагрегированный столбец, которого нет в GROUP BY.
В каждом отделе много сотрудников, поэтому в каждой группе много имён. Движок не может выбрать одно из них, поэтому стандартный SQL отклоняет запрос.
-- ERROR: name is not in GROUP BY and not aggregated
SELECT department, name, COUNT(*)
FROM employees
GROUP BY department;Два способа исправить ошибку
Есть два корректных способа исправления, и интервьюер хочет услышать, что Вы понимаете: оба дают разные результаты:
- Добавить столбец в GROUP BY, если Вам действительно нужна более детальная группировка (одна строка на отдел и имя).
- Обернуть его в агрегатную функцию, например
MAX(name)илиCOUNT(name), если Вам нужно одно значение для каждой существующей группы.
-- Finer grouping
SELECT department, name, COUNT(*) AS rows_for_person
FROM employees
GROUP BY department, name;ONLY_FULL_GROUP_BY в MySQL
Любимая ловушка: старые версии MySQL разрешали выбирать столбцы, не входящие в группировку, и молча возвращали произвольное значение из группы. Так появлялись неправильные отчёты, которые выглядели вполне корректно.
Современный MySQL по умолчанию включает ONLY_FULL_GROUP_BY, который обеспечивает соблюдение стандартного правила. PostgreSQL, SQL Server и Oracle всегда его соблюдали. Если Вас спросят, почему запрос «работал на старом сервере, а теперь перестал», это и есть ответ.
-- Legal under ONLY_FULL_GROUP_BY because every
-- selected column is grouped or aggregated
SELECT department, MAX(hire_date) AS latest_hire
FROM employees
GROUP BY department;Исключение для функциональной зависимости
Есть нюанс, с помощью которого интервьюеры проверяют глубину понимания. Если выполнить группировку по первичному ключу таблицы, каждый другой столбец этой таблицы функционально зависит от ключа, поэтому в каждой группе у него ровно одно значение.
PostgreSQL и современные версии MySQL разрешают выбирать такие зависимые столбцы, не перечисляя их отдельно. Сгруппированный ключ однозначно определяет эти столбцы, поэтому неоднозначности нет.
-- Legal: id is the PK, so name is determined by it
SELECT e.id, e.name, COUNT(o.id) AS orders
FROM employees e
LEFT JOIN orders o ON o.employee_id = e.id
GROUP BY e.id;Разбор примера: продажи по регионам
Предположим, Вам нужно составить отчёт об общем объёме продаж по регионам. Ключ группировки — region, показатель — SUM(amount). Всё остальное нужно агрегировать или исключить.
Обратите внимание, насколько чисто выглядит результат: одна строка на регион, содержащая одно суммарное значение. Именно такую структуру имеет любой агрегатный отчёт.
SELECT region,
SUM(amount) AS total_sales,
COUNT(*) AS num_orders,
AVG(amount) AS avg_order
FROM sales
GROUP BY region;Сочетание детализации и итогов
Хитрый вопрос: «Показать сумму каждого заказа вместе с общей суммой по его региону». С помощью обычного GROUP BY сделать это нельзя, потому что группировка уничтожает отдельные строки.
Правильный ответ — оконная функция (SUM(amount) OVER (PARTITION BY region)) или повторное соединение с подзапросом, в котором выполнена группировка. Суть вопроса — распознать, что GROUP BY здесь является неподходящим инструментом.
-- Detail rows kept, region total added per row
SELECT order_id, region, amount,
SUM(amount) OVER (PARTITION BY region) AS region_total
FROM sales;GROUP BY и псевдонимы SELECT
Можно ли выполнить GROUP BY по псевдониму, определённому в SELECT? Это зависит от диалекта, и именно эту непоследовательность интервьюеры часто проверяют.
- MySQL и PostgreSQL: разрешают группировку по псевдониму SELECT.
- SQL Server и Oracle: не разрешают; нужно повторить полное выражение.
Переносимый вариант — повторить выражение в GROUP BY: он работает везде.
-- Portable: repeat the expression rather than the alias
SELECT EXTRACT(YEAR FROM order_date) AS yr, COUNT(*)
FROM sales
GROUP BY EXTRACT(YEAR FROM order_date);DISTINCT и GROUP BY для получения уникальных строк
Если Вам нужны только уникальные комбинации без агрегата, GROUP BY без агрегатной функции ведёт себя как DISTINCT. На собеседовании могут спросить, какой вариант понятнее.
Используйте DISTINCT, чтобы явно выразить намерение: «Мне нужны уникальные строки». Оставляйте GROUP BY для случаев, когда Вы также вычисляете агрегаты. Результат один и тот же, но смысловая подсказка для читающего отличается.
-- These return the same rows
SELECT DISTINCT department, role FROM employees;
SELECT department, role FROM employees GROUP BY department, role;Как ответить на собеседовании
Когда Вам задают вопрос о GROUP BY, проговорите правило вслух: «Каждый выбранный столбец является либо ключом группировки, либо обёрнут в агрегатную функцию, потому что после группировки на каждый ключ остаётся одна строка».
Затем назовите ключ группировки и показатели и убедитесь, что ни один столбец не используется без группировки. Такой структурированный ответ показывает компетентность специалиста среднего уровня ещё до написания запроса.
Быстрая проверка
Проверьте, насколько хорошо Вы усвоили основное правило GROUP BY.
Итоги
Правило: каждый столбец SELECT — это ключ группировки или агрегатная функция. Почему: GROUP BY оставляет одну строку на ключ, поэтому негруппированные исходные столбцы неоднозначны.
- Исправляйте нарушения: добавляйте столбец в группировку или применяйте к нему агрегатную функцию.
- Прежнее поведение MySQL возвращало произвольные значения;
ONLY_FULL_GROUP_BYобеспечивает соблюдение стандарта. - Функциональная зависимость от первичного ключа — единственное допустимое исключение.
- Чтобы сохранить детальные строки рядом с итогами групп, используйте оконные функции, а не GROUP BY.
Часто задаваемые вопросы
Урок «Правило GROUP BY для столбцов SELECT» бесплатный?
Да — полный текст урока «Правило GROUP BY для столбцов SELECT» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Coding Interview Prep, подпишись на CoddyKit PRO. Курс Coding Interview Prep содержит 4 уроков всего.
Чему я научусь в уроке «Правило GROUP BY для столбцов SELECT»?
Узнайте, почему каждый неагрегированный столбец должен присутствовать в GROUP BY, и разберитесь с режимом only-full-group-by. Ты практикуешь Coding Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Coding Interview Prep?
Предыдущий опыт не требуется. Coding Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Правило GROUP BY для столбцов SELECT»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Coding Interview Prep?
Да. Каждый урок Coding Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Правило GROUP BY для столбцов SELECT
- HAVING и WHERE
- Группировка по нескольким столбцам и выражениям
- Подсчёт и фильтрация групп