ML Vault
All notes

GROUP BY

Логика:

  1. Сначала в таблице определяются строки, в которых в указанном в GROUP BY столбце есть одинаковые значения.
  2. Далее по этим значениям записи объединяются в группы, причём в группе может быть даже одна запись.
  3. После этого с помощью агрегирующих функций над элементами этих групп, как правило, проводятся определённые операции. Например, с помощью SUM вычисляется сумма значений в каком-либо столбце в каждой группе:
SELECT column_1, SUM(column_2) AS sum
FROM table
GROUP BY column_1

Уточнения:

  • группировку можно делать сразу по нескольким колонкам:
SELECT column_1, column_2, SUM(column_3) AS sum
FROM table
GROUP BY column_1, column_2
  • к группам, образовавшимся в результате GROUP BY, можно применять сразу несколько агрегирующих функций (в том числе к разным колонкам):
SELECT column_1, SUM(column_2) AS sum, AVG(column_3) AS avg
FROM table
GROUP BY column_1
  • агрегирующую функцию можно применить к той же самой колонке, по которой осуществляется группировка (Не всегда такая операция имеет смысл, но она допустима. Например, с помощью функции COUNT можно посчитать количество записей, попавших в каждую группу.):
SELECT column_1, COUNT(column_1) AS count
FROM table
GROUP BY column_1
  • после группировки к результатам агрегирующих функций можно применять другие функции. Также над ними можно сразу проводить арифметические операции
  • агрегацию не обязательно проводить по уже имеющимся колонкам — можно сначала применить некоторую функцию в колонке из исходной таблицы, а затем сразу провести агрегацию по новой колонке:
SELECT column_1, SUM(some_function(column_2)) AS sum_over_function
FROM table
GROUP BY column_1
  • группировку можно делать сразу по новым полям, посчитанным в SELECT. При этом допускается использование в GROUP BY алиаса колонки, указанного в SELECT, но это синтаксический сахар в PostgreSQL, в других СУБД его может не быть, поэтому не рекомендуется так делать. Cледующие запросы дадут одинаковый результат:
SELECT DATE(column_1) AS date, SUM(column_2) AS sum
FROM table
GROUP BY DATE(column_1)


SELECT DATE(column_1) AS date, SUM(column_2) AS sum
FROM table
GROUP BY date
  • делать агрегацию после группировки не обязательно. Если не указать агрегирующую функцию, то запрос вернёт уникальные значения в столбце (или уникальные комбинации значений в столбцах), т.е. тот же результат, что и оператор DISTINCT (частый вопрос на собесах):
SELECT user_id
FROM user_actions
GROUP BY user_id


SELECT DISTINCT user_id
FROM user_actions
  • при использовании группировки колонки, указанные в SELECT, должны находиться и в GROUP BY, если они не используются в агрегирующих функциях. Это обязательное условие, и если оно не будет выполнено, то база данных вернёт ошибку. В обратную сторону указанное выше правило не работает: если мы что-то указали в GROUP BY, то это совсем не обязательно указывать в SELECT
  • группировка всегда выполняется после фильтрации, т.е. сначала выполняются инструкции в WHERE и только потом данные группируются с помощью GROUP BY
  • вместо названий колонок в блоке GROUP BY можно использовать порядковые номера колонок, указанных в SELECT. Например, следующие запросы эквивалентны:
SELECT column_1, column_2, SUM(column_3) AS sum
FROM table
GROUP BY column_1, column_2


SELECT column_1, column_2, SUM(column_3) AS sum
FROM table
GROUP BY 1, 2
  • При этом номера колонок из SELECT можно также использовать при сортировке в операторе ORDER BY:
SELECT column_1, column_2, SUM(column_3) AS sum
FROM table
GROUP BY 1, 2
ORDER BY 3