GROUP BY aggregates rows sharing the same column values so you can compute totals, averages, counts, and other statistics per group.
GROUP BY collapses rows that share the same value(s) in specified column(s) into a single group, allowing aggregate functions like COUNT(), SUM(), AVG(), MIN(), and MAX() to run once per group instead of once per row.
After grouping, PostgreSQL applies the aggregate functions listed in the SELECT clause to each group. Columns in SELECT that are not wrapped in an aggregate must appear in the GROUP BY list.
Use SELECT, include aggregates or grouping columns, add GROUP BY followed by the same non-aggregated columns. Optionally chain ORDER BY and HAVING to sort or filter grouped results.
Yes. Provide a comma-separated list: GROUP BY column1, column2. PostgreSQL forms a distinct group for every unique combination of those columns.
HAVING applies conditions after grouping. Use it to keep or discard groups based on aggregate values (e.g., HAVING COUNT(*) > 10).
SELECT c.id,
c.name,
COUNT(o.id) AS total_orders,
SUM(o.total_amount) AS lifetime_value
FROM Customers AS c
JOIN Orders AS o ON o.customer_id = c.id
GROUP BY c.id, c.name
ORDER BY lifetime_value DESC;
This query shows how many orders each customer placed and their total spend, ranked from highest to lowest.
1. Index grouping columns to accelerate grouping. 2. Avoid SELECT *; list only needed columns and aggregates. 3. Use integer or enum columns instead of large text fields when possible to reduce sort cost.
Missing columns in GROUP BY: Any non-aggregated column in SELECT must be in GROUP BY. Fix by adding the column or wrapping it in an aggregate.
Using WHERE instead of HAVING for aggregates: WHERE filters rows before grouping, so conditions on aggregates belong in HAVING.
Grouping introduces sorting or hashing overhead, but proper indexing and limiting columns keep performance acceptable.
Yes. Expressions or functions (e.g., DATE_TRUNC('month', order_date)) are allowed; just repeat the same expression in SELECT or use column aliases in PostgreSQL 9.6+.
Yes in PostgreSQL 9.6+. Define the alias in SELECT, then reference it in GROUP BY for cleaner queries.
PostgreSQL may use hashing instead of sorting. To guarantee order, add ORDER BY explicitly.
Create indexes on grouping columns, aggregate pre-sorted data, or use partial aggregations in window functions.