Beginner: asking questions · Aggregation: GROUP BY and HAVING · topic 17 of 62 · 35 min
GROUP BY
Explanation
One row per group
The last topic gave one number for the whole table. Usually you want that number for each group: how many students in each city, the total of each order, the average salary in each department. GROUP BY column puts rows with the same value in that column into one group, then each aggregate runs separately for every group.
SELECT city, COUNT(*) AS students
FROM students
GROUP BY city;
-- Chennai | 1
-- Delhi | 2
-- Hyderabad | 1
-- Mumbai | 1
-- Pune | 3Totals per order
order_items has one row per product in an order. To get each order's value, group the lines by order_id and add up qty × price.
SELECT order_id, SUM(qty * price) AS order_total
FROM order_items
GROUP BY order_id;
-- 101 | 1780
-- 102 | 1999
-- 103 | 2248 ... 8 ordersSeveral aggregates at once, and the NULL group
SELECT dept_id, COUNT(*) AS employees, ROUND(AVG(salary), 2) AS avg_salary
FROM employees
GROUP BY dept_id;
-- NULL | 1 | 45000
-- 1 | 4 | 140000
-- 2 | 3 | 80666.67
-- 3 | 2 | 86500
-- 4 | 1 | 80000The golden rule
After grouping, each result row stands for a whole group. A column in GROUP BY has one value per group, so it can be shown. A column inside an aggregate becomes one value per group, so it can be shown. Any other column has many values in the group, and SQL cannot know which one to show. So: every selected column is either grouped or aggregated.
SELECT city, name, MAX(marks) FROM students GROUP BY city; -- name is neither!Grouping by more than one column
GROUP BY city, course makes one group for each different (city, course) pair. Pune with BCA, Pune with BCom and Pune with BSc are three groups. The more columns, the smaller the groups.
SELECT category, COUNT(*) AS products, MIN(price) AS cheapest, MAX(price) AS dearest
FROM products
GROUP BY category
ORDER BY category;
-- Electronics | 2 | 1299 | 1999
-- Fashion | 2 | 899 | 2499
-- Grocery | 2 | 160 | 650
-- Kitchen | 2 | 450 | 1450Ordering groups
GROUP BY does not promise any order (SQLite often returns groups sorted, but that is a side effect). Add ORDER BY. You can sort by a grouped column, by an aggregate, or by its alias: ORDER BY students DESC gives the biggest city first. With ties, add a tie-breaker such as ORDER BY students DESC, city.
Where GROUP BY sits in a query
Written order: SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT. WHERE comes before GROUP BY, so it filters rows before they are put into groups. The next topic adds HAVING, which filters whole groups.
Common mistakes
- Selecting a column that is neither grouped nor aggregated. Add it to GROUP BY, or wrap it in an aggregate.
- Grouping by too many columns (for example by id), so every group has one row and nothing is summarised.
- Expecting groups to come out sorted. Always write ORDER BY.
- Forgetting the NULL group. Rows with a NULL key form their own group; filter them with WHERE col IS NOT NULL or label them with COALESCE.
- Grouping by a display name that is not unique, so two different customers called "Ravi Kumar" merge into one group. Group by the id, and show the name alongside (module 5 shows how with a JOIN).
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
GROUP BY · 1/7
Most reports want a number for each group: students per city, total per order, average salary per department.
Prefer a video by a teacher? Find free videos on “sql group by tutorial count per group beginners” on YouTube ↗
In real life: Sales per category for a weekly review
Retail chains review sales by category every week: how many items, how much revenue, which category is growing. The query behind such a table is a GROUP BY category with COUNT and SUM. The same pattern gives patients per ward in a hospital, tickets per train in a booking system, or complaints per district on a government portal.
SELECT category,
COUNT(*) AS products,
SUM(stock) AS units
FROM products
GROUP BY category
ORDER BY units DESC;Practice (0/4 done)
How many students live in each city? Return city and the number of students, named students.
Work out the value of every order. From order_items, return order_id and the sum of qty * price, named order_total.
For each dept_id in employees (COMPANY), return dept_id, the number of employees named employees, and the average salary rounded to 2 decimal places named avg_salary. Keep the group of people with no department.
For each product category, return category, the number of products named products, the lowest price named cheapest and the highest price named dearest, sorted by category A to Z.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- HAVING versus WHEREAggregation: GROUP BY and HAVING · same module
- Conditional aggregation and string aggregationAggregation: GROUP BY and HAVING · same module
- GROUP BY and HAVINGBackend Development · SQL in depth
- Counting and totals: aggregate functionsBackend Development · Databases and SQL basics
- OVER and PARTITION BYWindow functions
- Correlated subqueries and derived tablesSubqueries, CTEs and set operations
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
students has 8 rows in 5 different cities. How many rows does SELECT city, COUNT(*) FROM students GROUP BY city return?
Answer: 5
GROUP BY gives one row per group, and there are 5 cities.
Which query follows the GROUP BY rule?
Answer: SELECT dept_id, AVG(salary) FROM employees GROUP BY dept_id
dept_id is grouped and salary is aggregated; name is neither in the other options.
Two employees have dept_id NULL. After GROUP BY dept_id, where are they?
Answer: In one NULL group together
All NULLs fall into a single group.
What does GROUP BY city, course group together?
Answer: Rows with the same city AND the same course
Each different combination of the grouped columns is one group.
Your GROUP BY results came out sorted by city in SQLite. Is that guaranteed?
Answer: No; add ORDER BY if the order matters
Any order without ORDER BY is a side effect that can change.
You want to ignore cancelled orders before adding up totals per city. Where does status <> 'cancelled' go?Related
Answer: In WHERE
It is a test on single rows, so it belongs in WHERE, which runs before grouping.
From GROUP BY and HAVING
What does SELECT city, SUM(amount) FROM orders GROUP BY city return?Related
Answer: One row per city with its total
GROUP BY city makes one group per city, and SUM runs on each group.
SELECT city, COUNT(*) AS n FROM students GROUP BY city HAVING n > 1 works in SQLite. What happens in PostgreSQL?Related
Answer: It fails, because a SELECT alias is not visible in HAVING
HAVING runs before SELECT in standard SQL. Write HAVING COUNT(*) > 1.
From HAVING versus WHERE
employees has 11 rows. How many rows does SELECT name, AVG(salary) OVER (PARTITION BY dept_id) FROM employees return?Related
Answer: 11
A window function never removes rows; each of the 11 rows gets its department average.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 3 more topics in “Aggregation: GROUP BY and HAVING” before its exam: HAVING versus WHERE, Conditional aggregation and string aggregation, Writing reports with aggregation.
- Module 4 exam: Aggregation, GROUP BY and HAVING · 15 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, JOINs. 62 topics left in the course before the final exam.