SQL exercises with solutions: COUNT, SUM, AVG, MIN, MAX

SQL exercises with solutions: COUNT, SUM, AVG, MIN, MAX

Updated on

Aggregates sum up many rows into one value: COUNT, SUM, AVG, MIN, MAX. These 3 exercises range from level 1 to level 2; they use the syntax of SQLite, SpeedQL’s SQL engine.

Tip: COUNT(*) counts rows; COUNT(column) skips NULL values.

Read the “COUNT, SUM, AVG, MIN, MAX” card in the cheat sheet

Exercise 1 · level 1

Show the total number of products.

Table products (6 rows)
idnamecategorypricestock
1KeyboardOffice2540
2MouseOffice150
3ScreenDisplay18012
4HeadsetAudio608
5WebcamOffice450
6SpeakerAudio3525
Show the hint

Topics to use: COUNT, SUM, AVG, MIN, MAX.

Query structure:

SELECT COUNT(*)
FROM …
Show the solution
SELECT COUNT(*)
FROM products;

Expected result (1 row):

COUNT(*)
6

Exercise 2 · level 1

Show the highest salary among all employees.

Table employees (8 rows)
idnamedepartmentsalary
1AliceFinance32000
2BobIT41000
3ClaireFinance38000
4DavidHR29000
5EmmaIT50000
6FaridIT47000
7GaelleHR33000
8HugoFinance44000
Show the hint

Topics to use: COUNT, SUM, AVG, MIN, MAX.

Query structure:

SELECT MAX(…)
FROM …
Show the solution
SELECT MAX(salary)
FROM employees;

Expected result (1 row):

MAX(salary)
50000

Exercise 3 · level 2

Show the number of draws (both teams scored the same number of goals) and the total number of goals scored in those matches.

Table matches (10 rows)
idplayed_onhome_idaway_idhome_goalsaway_goals
12025-08-021221
22025-08-033400
32025-08-095113
42025-08-102322
52025-08-164531
62025-08-171310
72025-08-232401
82025-08-243523
92025-08-304111
102025-08-315202
Show the hint

Topics to use: WHERE (filters), COUNT, SUM, AVG, MIN, MAX.

Query structure:

SELECT COUNT(*), SUM(… + …)
FROM …
WHERE … = …
Show the solution
SELECT COUNT(*), SUM(home_goals + away_goals)
FROM matches
WHERE home_goals = away_goals;

Expected result (1 row):

COUNT(*)SUM(home_goals + away_goals)
36

More exercises: level 5 of the SQL course, “Summarising a table: aggregates”

These 5 exercises come from level 5 of the course, on other tables. Each one has written hints and its solution, folded by default.

Exercise 4 · course, level 5 · Guided

How many books are there in the books table?

Table books (10 rows)
idtitleauthor_idgenrepagesyear
1Cold River1Novel3202011
2Salt Roads2Travel2102016
3The Glass Hive3Sci-Fi4122019
4Winter Ledger1Crime2882014
5Desert Letters2Novel3562020
6Small Engines4Sci-Fi1982022
7Harbor Lights5Novel4452008
8Night Garden3Crime3012017
9Paper Birds5Poetry962012
10Open Maps4Travel2402021
Show the hints

Hint: SELECT COUNT(*) FROM books;

Show the solution
SELECT COUNT(*) AS nb_books
FROM books;

Expected result (1 row):

nb_books
10

COUNT(*) counts every row of the table.

Exercise 5 · course, level 5 · Practice

How many seats were sold in total, across all flights?

Table flights (12 rows)
idairlineorigindestdepartsduration_minpriceseats_soldcapacity
1SkyJetCDGMAD2025-06-01 08:1012589150180
2AirNovaCDGLIS2025-06-01 11:40155120160170
3BlueWingLYSFCO2025-06-02 07:309575110150
4SkyJetMADCDG2025-06-02 18:2012095170180
5AirNovaBERCDG2025-06-03 09:05110105140160
6BlueWingNCEBER2025-06-03 13:5013014090150
7SkyJetCDGFCO2025-06-04 06:4513599175180
8AirNovaLISMAD2025-06-04 16:15756560120
9BlueWingFCOLYS2025-06-05 20:3010082130150
10SkyJetCDGBER2025-06-05 10:00105110120180
11AirNovaMADLIS2025-06-06 12:25807095120
12BlueWingLYSMAD2025-06-06 15:4011579100150
Show the hints

Hint 1 · lead: You need to add up a column over all the rows.

Hint 2 · method: Add up the seats_sold column with SUM.

Show the solution
SELECT SUM(seats_sold) AS total_seats
FROM flights;

Expected result (1 row):

total_seats
1500

SUM adds up the column over all the rows.

Exercise 6 · course, level 5 · Practice

Show the date of the first loan (first_loan) and the date of the last loan (last_loan).

The requested column names matter.

Table loans (12 rows)
idbook_idmember_idloan_datereturn_date
1112025-01-052025-01-19
2322025-01-102025-02-02
3512025-02-012025-02-10
4732025-02-03NULL
5342025-02-152025-03-01
6222025-03-022025-03-30
7852025-03-05NULL
8132025-03-102025-03-18
9612025-03-202025-04-15
10352025-04-01NULL
11942025-04-052025-04-12
121022025-04-082025-04-20
Show the hints

Hint 1 · lead: MIN and MAX are not only for numbers.

Hint 2 · method: MIN(loan_date) AS first_loan and MAX(loan_date) AS last_loan.

Show the solution
SELECT MIN(loan_date) AS first_loan, MAX(loan_date) AS last_loan
FROM loans;

Expected result (1 row):

first_loanlast_loan
2025-01-052025-04-08

In the YYYY-MM-DD format, alphabetical order is also chronological order: MIN gives the oldest date, MAX the most recent.

Exercise 7 · course, level 5 · Practice

How many contacts have an email address?

Table contacts (5 rows)
idnameemailphonecity
1Alice Martinalice@mail.com0612345678Paris
2bob durandNULL0698765432Lyon
3CLAIRE ROUXclaire@work.orgNULLNULL
4David LefevreNULLNULLNantes
5Emma Petitemma@mail.com0611223344NULL
Show the hints

Hint 1 · lead: One of the two forms of COUNT ignores empty cells.

Hint 2 · method: COUNT(email) only counts the non-empty emails.

Show the solution
SELECT COUNT(email) AS with_email
FROM contacts;

Expected result (1 row):

with_email
3

COUNT(*) would have given 5; COUNT(email) ignores the 2 contacts without an email.

Exercise 8 · course, level 5 · Challenge

For the maths grades, show on a single row: the number of grades (nb_grades), their average rounded to one decimal place (avg_math) and the gap between the best and the worst grade (spread).

The requested column names matter.

Table grades (18 rows)
idstudent_idsubjectgradeterm
11math151
21french121
31math172
42math91
52french141
62math112
73math131
83history161
94math181
104french161
114math192
125french81
135math101
146math141
156history111
… and 3 more rows
Show the hints

Hint 1 · lead: First filter the maths grades. A calculation can combine two aggregates, just as it combines two columns.

Hint 2 · method: WHERE subject = 'math', then COUNT(*), ROUND(AVG(grade), 1) and MAX(grade) - MIN(grade).

Show the solution
SELECT COUNT(*) AS nb_grades,
       ROUND(AVG(grade), 1) AS avg_math,
       MAX(grade) - MIN(grade) AS spread
FROM grades
WHERE subject = 'math';

Expected result (1 row):

nb_gradesavg_mathspread
91410

WHERE applies before the three aggregates, which therefore only see the maths grades. MAX(grade) - MIN(grade) is a calculation between two aggregates.

Practice with automatic checking

In SpeedQL, you write your query and it is checked straight away, on these tables and then on a hidden dataset.

Practice on the 7 “COUNT, SUM, AVG, MIN, MAX” questions