SQL exercises with solutions: GROUP BY

SQL exercises with solutions: GROUP BY

Updated on

GROUP BY computes one summary per group: one result row per value of the column. These 15 exercises range from level 2 to level 3; they use the syntax of SQLite, SpeedQL’s SQL engine.

Tip: Every column shown without an aggregate must appear in the GROUP BY.

Read the “GROUP BY” card in the cheat sheet

Exercise 1 · level 2

For each department, show the department and its number of 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, GROUP BY.

Query structure:

SELECT , COUNT(*)
FROM 
GROUP BY 
Show the solution
SELECT department, COUNT(*)
FROM employees
GROUP BY department;

Expected result (3 rows):

departmentCOUNT(*)
Finance3
HR2
IT3

Exercise 2 · level 2

For each department, show the department and the average salary of its 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, GROUP BY.

Query structure:

SELECT , AVG()
FROM 
GROUP BY 
Show the solution
SELECT department, AVG(salary)
FROM employees
GROUP BY department;

Expected result (3 rows):

departmentAVG(salary)
Finance38000
HR31000
IT46000

Exercise 3 · level 2

For each department, show the department and the total of the salaries paid.

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

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

Query structure:

SELECT , SUM()
FROM 
GROUP BY 
Show the solution
SELECT department, SUM(salary)
FROM employees
GROUP BY department;

Expected result (3 rows):

departmentSUM(salary)
Finance114000
HR62000
IT138000

Exercise 4 · level 2

For each category, show the category and the total stock of its products.

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

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

Query structure:

SELECT , SUM()
FROM 
GROUP BY 
Show the solution
SELECT category, SUM(stock)
FROM products
GROUP BY category;

Expected result (3 rows):

categorySUM(stock)
Audio33
Display12
Office40

Exercise 5 · level 2

For each genre, show the genre and the number of movies.

Table movies (10 rows)
idtitlegenreyeardurationratingdirector_id
1Night TrainThriller20151187.81
2Blue HarborDrama20181027.12
3Paper Moon CityComedy2012956.45
4Silent PeakDrama20201318.23
5Last SignalSci-Fi20191427.51
6Summer KeysComedy2016885.94
7Iron GardenSci-Fi202112583
8Dust and GoldWestern20141106.82
9The Quiet HourDrama2022977.45
10Deep CurrentThriller20171056.9NULL
Show the hint

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

Query structure:

SELECT , COUNT(*)
FROM 
GROUP BY 
Show the solution
SELECT genre, COUNT(*)
FROM movies
GROUP BY genre;

Expected result (5 rows):

genreCOUNT(*)
Comedy2
Drama3
Sci-Fi2
Thriller2
Western1

Exercise 6 · level 2

For each city, show the city and the number of members.

Table members (6 rows)
idnamecityjoined
1LenaLyon2022-01-15
2MarcParis2021-06-03
3NadiaLyon2023-03-20
4OscarLille2020-11-11
5PaulaParis2024-02-01
6QuentinNantes2023-09-09
Show the hint

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

Query structure:

SELECT , COUNT(*)
FROM 
GROUP BY 
Show the solution
SELECT city, COUNT(*)
FROM members
GROUP BY city;

Expected result (4 rows):

cityCOUNT(*)
Lille1
Lyon2
Nantes1
Paris2

Exercise 7 · level 2

For each airline, show the airline, the number of flights and the average price.

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 hint

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

Query structure:

SELECT , COUNT(*), AVG()
FROM 
GROUP BY 
Show the solution
SELECT airline, COUNT(*), AVG(price)
FROM flights
GROUP BY airline;

Expected result (3 rows):

airlineCOUNT(*)AVG(price)
AirNova490
BlueWing494
SkyJet498.25

Exercise 8 · level 2

For each genre, show the genre, the number of songs and the average duration in seconds.

Table songs (10 rows)
idtitleartist_idgenreduration_sreleased
1Glass Heart1Pop2142019-04-12
2Low Tide1Pop1982021-06-01
3Rust2Rock2562008-09-30
4Wires2Rock3012015-02-14
5Sunday Market3Afrobeat2332020-11-20
6Palm Wine3Afrobeat2452022-03-03
7Alma4Latin1892013-07-07
8Brisa4Pop2052018-05-25
9Night Drive5Electro2762021-10-10
10Pulse5Electro2302023-01-15
Show the hint

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

Query structure:

SELECT , COUNT(*), AVG()
FROM 
GROUP BY 
Show the solution
SELECT genre, COUNT(*), AVG(duration_s)
FROM songs
GROUP BY genre;

Expected result (5 rows):

genreCOUNT(*)AVG(duration_s)
Afrobeat2239
Electro2253
Latin1189
Pop3205.66666666666666
Rock2278.5

Exercise 9 · level 2

For each city, show the city, the highest maximum temperature recorded and the lowest minimum temperature recorded.

Table readings (15 rows)
idcitydaytemp_maxtemp_minrain_mm
1Paris2025-07-0124150
2Paris2025-07-0227170
3Paris2025-07-0322164.5
4Paris2025-07-04191412
5Paris2025-07-0523130
6Lyon2025-07-0126160
7Lyon2025-07-0229180
8Lyon2025-07-0331190
9Lyon2025-07-0424178.5
10Lyon2025-07-0522153
11Marseille2025-07-0130210
12Marseille2025-07-0232220
13Marseille2025-07-0333230
14Marseille2025-07-0429210
15Marseille2025-07-0528200
Show the hint

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

Query structure:

SELECT , MAX(), MIN()
FROM 
GROUP BY 
Show the solution
SELECT city, MAX(temp_max), MIN(temp_min)
FROM readings
GROUP BY city;

Expected result (3 rows):

cityMAX(temp_max)MIN(temp_min)
Lyon3115
Marseille3320
Paris2713

Exercise 10 · level 2

For each room type, show the type and the average price rounded to 1 decimal.

Table rooms (10 rows)
idhotel_idtypeprice
11single70
21double95
32double130
42suite210
53single110
63double150
74double65
85double260
95suite480
105single190
Show the hint

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

Query structure:

SELECT , ROUND(AVG(), )
FROM 
GROUP BY 
Show the solution
SELECT type, ROUND(AVG(price), 1)
FROM rooms
GROUP BY type;

Expected result (3 rows):

typeROUND(AVG(price), 1)
double140
single123.3
suite345

Exercise 11 · level 2

For each order status, show the status and the number of orders.

Table orders (8 rows)
idcustomer_idorder_datestatus
112025-01-05shipped
222025-01-12shipped
312025-02-03paid
432025-02-10cancelled
542025-02-20shipped
652025-03-02shipped
722025-03-15paid
832025-03-28shipped
Show the hint

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

Query structure:

SELECT , COUNT(*)
FROM 
GROUP BY 
Show the solution
SELECT status, COUNT(*)
FROM orders
GROUP BY status;

Expected result (3 rows):

statusCOUNT(*)
cancelled1
paid2
shipped5

Exercise 12 · level 2

For each status, show the status and the total number of hours of the tasks.

Table tasks (10 rows)
idproject_iddev_idtitlehoursstatusdone_on
111Landing page12done2025-03-10
213Data model20done2025-03-20
312Login8doingNULL
424ETL job16done2025-04-02
525CI pipeline6done2025-03-15
631Dashboard14todoNULL
733Report10done2025-04-25
842API18doingNULL
945Monitoring9todoNULL
1044Forecast22done2025-05-05
Show the hint

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

Query structure:

SELECT , SUM()
FROM 
GROUP BY 
Show the solution
SELECT status, SUM(hours)
FROM tasks
GROUP BY status;

Expected result (3 rows):

statusSUM(hours)
doing26
done86
todo23

Exercise 13 · level 2

For each account with transactions, show the account id (account_id) and its balance (sum of the amounts).

Table transactions (14 rows)
idaccount_idmade_onamountlabel
112025-01-022500salary
212025-01-05-60groceries
312025-01-12-800rent
422025-01-15500transfer
532025-01-031900salary
632025-01-20-120groceries
732025-02-01-950rent
842025-01-252100salary
942025-02-03-45restaurant
1012025-02-022600salary
1112025-02-06-75groceries
1252025-02-1030interest
1322025-02-15500transfer
1442025-02-18-600rent
Show the hint

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

Query structure:

SELECT , SUM()
FROM 
GROUP BY 
Show the solution
SELECT account_id, SUM(amount)
FROM transactions
GROUP BY account_id;

Expected result (5 rows):

account_idSUM(amount)
14165
21000
3830
41455
530

Exercise 14 · level 3

For each department, show the department, the number of employees and the average salary, from the highest to the lowest average salary.

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

Topics to use: ORDER BY, LIMIT, COUNT, SUM, AVG, MIN, MAX, GROUP BY.

Query structure:

SELECT , COUNT(*), AVG()
FROM 
GROUP BY 
ORDER BY AVG() DESC
Show the solution
SELECT department, COUNT(*), AVG(salary)
FROM employees
GROUP BY department
ORDER BY AVG(salary) DESC;

Expected result (3 rows, in this order):

departmentCOUNT(*)AVG(salary)
IT346000
Finance338000
HR231000

Exercise 15 · level 3

Show the department with the highest average salary.

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

Topics to use: ORDER BY, LIMIT, COUNT, SUM, AVG, MIN, MAX, GROUP BY.

Query structure:

SELECT 
FROM 
GROUP BY 
ORDER BY AVG() DESC
LIMIT 
Show the solution
SELECT department
FROM employees
GROUP BY department
ORDER BY AVG(salary) DESC
LIMIT 1;

Expected result (1 row):

department
IT

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 27 “GROUP BY” questions