Что такое GROUP BY в SQL
Что проверяют
Считаете ли вы агрегаты в базе или тянете строки в приложение и складываете их в цикле. Для бэкендера на Java это ежедневная развилка, и заодно вопрос показывает, помните ли вы порядок выполнения запроса, из которого следует всё остальное.
Как отвечать
GROUP BY схлопывает строки с одинаковым значением ключа в одну, а к остальным колонкам применяются агрегатные функции. Логический порядок такой: FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY. Отсюда прямые следствия: WHERE отсекает строки до группировки, HAVING фильтрует уже готовые группы и умеет условия по агрегатам, а псевдоним из SELECT в WHERE недоступен.
SELECT customer_id, count(*) AS orders, sum(total) AS amount
FROM orders
WHERE created_at >= :from_date
GROUP BY customer_id
HAVING sum(total) > 100000;Детали, которые отличают уверенный ответ: count со звёздочкой считает строки, count по колонке пропускает пустые значения; все пустые значения ключа собираются в одну группу; по стандарту каждая неагрегированная колонка списка выборки обязана быть в группировке. Когда нужны и детали строк, и агрегат рядом с ними, группировка не нужна, берут оконную функцию.
В контексте Java уместно добавить, что результат группировки не ложится на сущность и требует проекции в отдельный объект, а перенос подсчёта в код через группировку коллекций оправдан только на заведомо малой выборке.
Где спотыкаются
Группируют после соединения один ко многим и суммируют колонку родительской таблицы. Строки размножились, сумма завышена, и ошибку не видно, пока цифру не сверят вручную. Лечится агрегацией в подзапросе до соединения.
Меняют местами WHERE и HAVING. Обычный фильтр, загнанный в HAVING, работает после группировки, не даёт применить индекс и заставляет базу перелопачивать лишние строки.
Ждут, что результат придёт упорядоченным по ключу группировки. Порядок зависит от выбранного плана, и без ORDER BY он не гарантирован ничем.