While basic aggregate functions compute a single summary across the entire table, real-world business reports require metrics broken down by category (e.g., "Average GPA per course" or "Total sales per region"). The GROUP BY clause collapses rows sharing identical values in specified columns into summary rows.
When the database engine executes GROUP BY course, it organizes the incoming rows into buckets by unique course name, and then evaluates aggregate functions separately for each bucket:
-- Calculate total students and average GPA per course
SELECT
course,
COUNT(*) AS total_students,
ROUND(AVG(gpa), 2) AS average_gpa
FROM students
GROUP BY course
ORDER BY average_gpa DESC;
| course | total_students | average_gpa |
|---|---|---|
| B.Tech | 1 | 3.92 |
| BCA | 2 | 3.80 |
| MCA | 1 | 3.68 |
You can group by multiple attributes to drill down into subcategories:
-- Calculate total payroll per department AND job title
SELECT
department,
job_title,
COUNT(emp_id) AS head_count,
SUM(salary) AS total_payroll
FROM employees
GROUP BY department, job_title
ORDER BY department ASC, total_payroll DESC;
GROUP BY and not inside an aggregate, the database doesn't know which row's value to pick for that bucket! Always group by all non-aggregated columns.
Next, let us learn how to filter grouped aggregates using the SQL HAVING Clause!