SQL Tutorial menu

SQL GROUP BY and HAVING

GROUP BY puts rows with the same value into groups, so an aggregate function can give one answer for each group.

GROUP BY Syntax

Example

sql
SELECT column, AGGREGATE_FUNCTION(column)
FROM table_name
WHERE condition
GROUP BY column
HAVING condition
ORDER BY column;

Count Students per City

Without GROUP BY, COUNT(*) gives one number for the whole table. With it, you get one number per city:

Example

sql
SELECT city, COUNT(*) AS total
FROM students
GROUP BY city
ORDER BY total DESC;
citytotal
Karachi3
Lahore2
Islamabad1

The database makes three groups (Karachi, Lahore, Islamabad) and counts the rows in each.

Several Aggregates per Group

Example

sql
SELECT city, COUNT(*) AS total, MAX(marks) AS best
FROM students
GROUP BY city
ORDER BY total DESC;
citytotalbest
Karachi378
Lahore288
Islamabad192

Every column in SELECT must either be in GROUP BY or be inside an aggregate function. SELECT city, name, COUNT(*) ... GROUP BY city is an error in most databases, because a city group has many names and SQL does not know which one to show.

GROUP BY with a Join

Joins and grouping work well together. This report shows how many students each course has and their average marks:

Example

sql
SELECT c.title,
       COUNT(s.id) AS students,
       ROUND(AVG(s.marks), 1) AS avg_marks
FROM courses AS c
LEFT JOIN students AS s ON s.course_id = c.id
GROUP BY c.id, c.title
ORDER BY c.id;
titlestudentsavg_marks
Web Development271.0
Python Programming286.5
Graphic Designing192.0
Digital Marketing0NULL

We used COUNT(s.id), not COUNT(*), so the course with no students shows 0 instead of 1.

HAVING: Filter the Groups

WHERE filters rows before they are grouped. HAVING filters groups after the aggregate is calculated. That is why aggregates can go in HAVING but not in WHERE.

Cities with more than one student:

Example

sql
SELECT city, COUNT(*) AS total
FROM students
GROUP BY city
HAVING COUNT(*) > 1;
citytotal
Karachi3
Lahore2

Courses whose students average more than 75 marks:

Example

sql
SELECT c.title, AVG(s.marks) AS avg_marks
FROM students AS s
JOIN courses AS c ON s.course_id = c.id
GROUP BY c.title
HAVING AVG(s.marks) > 75;
titleavg_marks
Graphic Designing92.0
Python Programming86.5

Web Development is left out, because its average is 71.

WHERE and HAVING Together

WHEREHAVING
FiltersSingle rowsGroups
RunsBefore groupingAfter grouping
Can use COUNT, AVG...NoYes

Example

sql
SELECT city, MAX(marks) AS top
FROM students
WHERE age > 18
GROUP BY city
HAVING MAX(marks) > 80
ORDER BY top DESC;
citytop
Islamabad92
Lahore88

First Hamza (18) is removed by WHERE. Then the groups are made, and Karachi is removed by HAVING because its best mark is 78.

Exercise

Exercise

You want only the cities that have at least 2 students. Where does the condition COUNT(*) >= 2 go?

Learn SQL with a teacher

Join the Full Stack Development course at Workownix, online or in Orangi Town, Karachi, and get a certificate.

See the course Ask on WhatsApp