Exercices SQL corrigés : CASE WHEN

Exercices SQL corrigés : CASE WHEN

Mis à jour le

CASE choisit une valeur selon des conditions, ligne par ligne. Ces 15 exercices vont du niveau 4 au niveau 7 ; ils utilisent la syntaxe de SQLite, le moteur SQL de SpeedQL.

Conseil : Les conditions sont testées dans l’ordre : la première vraie l’emporte.

Relire la fiche « CASE » de l’aide-mémoire

Exercice 1 · niveau 4

Affiche le nom de chaque employé et une colonne level qui vaut 'high' si son salaire est d'au moins 40000, sinon 'low'. Utilise CASE.

Table employees (8 lignes)
idnamedepartmentsalary
1AliceFinance32000
2BobIT41000
3ClaireFinance38000
4DavidHR29000
5EmmaIT50000
6FaridIT47000
7GaelleHR33000
8HugoFinance44000
Voir l’indice

Notions à utiliser : CASE.

Structure de la requête :

SELECT , CASE WHEN  >=  THEN  ELSE  END AS 
FROM 
Voir la correction
SELECT name, CASE WHEN salary >= 40000 THEN 'high' ELSE 'low' END AS level
FROM employees;

Résultat attendu (8 lignes) :

namelevel
Alicelow
Bobhigh
Clairelow
Davidlow
Emmahigh
Faridhigh
Gaellelow
Hugohigh

Exercice 2 · niveau 4

Affiche l'id de chaque facture et une colonne status qui vaut 'paid' si la facture a une date de paiement, sinon 'unpaid'. Utilise CASE.

Table invoices (6 lignes)
idclientissueddueamountpaid_on
1Acme2025-01-152025-02-1412002025-02-10
2Acme2025-03-012025-03-16800NULL
3Bolt2025-01-202025-03-064502025-03-01
4Bolt2025-02-252025-03-279502025-04-02
5Cyan2025-03-052025-05-04300NULL
6Cyan2024-12-102024-12-306002025-01-05
Voir l’indice

Notions à utiliser : CASE, NULL, COALESCE.

Structure de la requête :

SELECT , CASE WHEN  IS NULL THEN  ELSE  END AS 
FROM 
Voir la correction
SELECT id, CASE WHEN paid_on IS NULL THEN 'unpaid' ELSE 'paid' END AS status
FROM invoices;

Résultat attendu (6 lignes) :

idstatus
1paid
2unpaid
3paid
4paid
5unpaid
6paid

Exercice 3 · niveau 4

Affiche le titre de chaque film et une colonne length valant 'short' s'il dure moins de 100 minutes, 'medium' s'il dure au plus 120 minutes, sinon 'long'. Utilise CASE.

Table movies (10 lignes)
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
Voir l’indice

Notions à utiliser : CASE.

Structure de la requête :

SELECT , CASE WHEN  <  THEN  WHEN  <=  THEN  ELSE  END AS 
FROM 
Voir la correction
SELECT title, CASE WHEN duration < 100 THEN 'short' WHEN duration <= 120 THEN 'medium' ELSE 'long' END AS length
FROM movies;

Résultat attendu (10 lignes) :

titlelength
Night Trainmedium
Blue Harbormedium
Paper Moon Cityshort
Silent Peaklong
Last Signallong
Summer Keysshort
Iron Gardenlong
Dust and Goldmedium
The Quiet Hourshort
Deep Currentmedium

Exercice 4 · niveau 4

Affiche la date de chaque match et une colonne result valant 'home' si l'équipe à domicile gagne, 'away' si l'équipe à l'extérieur gagne, sinon 'draw' (colonnes : played_on, result). Utilise CASE.

Table matches (10 lignes)
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
Voir l’indice

Notions à utiliser : CASE.

Structure de la requête :

SELECT , CASE WHEN  >  THEN  WHEN  <  THEN  ELSE  END AS 
FROM 
Voir la correction
SELECT played_on, CASE WHEN home_goals > away_goals THEN 'home' WHEN home_goals < away_goals THEN 'away' ELSE 'draw' END AS result
FROM matches;

Résultat attendu (10 lignes) :

played_onresult
2025-08-02home
2025-08-03draw
2025-08-09away
2025-08-10draw
2025-08-16home
2025-08-17home
2025-08-23away
2025-08-24away
2025-08-30draw
2025-08-31away

Exercice 5 · niveau 4

Affiche l'id de chaque vol et une colonne slot valant 'morning' s'il part avant 12:00, 'afternoon' s'il part avant 18:00, sinon 'evening' (colonnes : id, slot). Utilise CASE.

Table flights (12 lignes)
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
Voir l’indice

Notions à utiliser : CASE, Texte et dates.

Structure de la requête :

SELECT , CASE WHEN STRFTIME(, ) <  THEN  WHEN STRFTIME(, ) <  THEN  ELSE  END AS 
FROM 
Voir la correction
SELECT id, CASE WHEN strftime('%H:%M', departs) < '12:00' THEN 'morning' WHEN strftime('%H:%M', departs) < '18:00' THEN 'afternoon' ELSE 'evening' END AS slot
FROM flights;

Résultat attendu (12 lignes) :

idslot
1morning
2morning
3morning
4evening
5morning
6afternoon
7morning
8afternoon
9evening
10morning
11afternoon
12afternoon

Exercice 6 · niveau 4

Affiche le nom et la ville de chaque hôtel, et une colonne category : 'luxury' pour 5 étoiles, 'comfort' pour 3 ou 4 étoiles, 'budget' sinon. Nomme les colonnes name, city et category.

Table hotels (5 lignes)
idnamecitystars
1Seaside InnNice3
2Alpine LodgeAnnecy4
3City LoftParis4
4Old MillBordeaux2
5Grand PalaceParis5
Voir l’indice

Notions à utiliser : CASE.

Structure de la requête :

SELECT , , CASE WHEN  =  THEN  WHEN  >=  THEN  ELSE  END AS 
FROM 
Voir la correction
SELECT name, city, CASE WHEN stars = 5 THEN 'luxury' WHEN stars >= 3 THEN 'comfort' ELSE 'budget' END AS category
FROM hotels;

Résultat attendu (5 lignes) :

namecitycategory
Seaside InnNicecomfort
Alpine LodgeAnnecycomfort
City LoftPariscomfort
Old MillBordeauxbudget
Grand PalaceParisluxury

Exercice 7 · niveau 4

Affiche le nom de chaque produit et une colonne size : 'small' sous 10, 'medium' de 10 à moins de 50, 'large' sinon. Nomme les colonnes name et size.

Table products (7 lignes)
idnamecategoryprice
1Desk LampHome35
2Coffee MugKitchen12
3NotebookOffice6
4Office ChairOffice149
5KettleKitchen45
6CushionHome22
7StaplerOffice9
Voir l’indice

Notions à utiliser : CASE.

Structure de la requête :

SELECT , CASE WHEN  <  THEN  WHEN  <  THEN  ELSE  END AS 
FROM 
Voir la correction
SELECT name, CASE WHEN price < 10 THEN 'small' WHEN price < 50 THEN 'medium' ELSE 'large' END AS size
FROM products;

Résultat attendu (7 lignes) :

namesize
Desk Lampmedium
Coffee Mugmedium
Notebooksmall
Office Chairlarge
Kettlemedium
Cushionmedium
Staplersmall

Exercice 8 · niveau 4

Affiche le numéro et le montant de chaque opération, et une colonne direction : 'credit' si le montant est positif, 'debit' sinon. Nomme les colonnes id, amount et direction.

Table transactions (14 lignes)
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
Voir l’indice

Notions à utiliser : CASE.

Structure de la requête :

SELECT , , CASE WHEN  >  THEN  ELSE  END AS 
FROM 
Voir la correction
SELECT id, amount, CASE WHEN amount > 0 THEN 'credit' ELSE 'debit' END AS direction
FROM transactions;

Résultat attendu (14 lignes) :

idamountdirection
12500credit
2-60debit
3-800debit
4500credit
51900credit
6-120debit
7-950debit
82100credit
9-45debit
102600credit
11-75debit
1230credit
13500credit
14-600debit

Exercice 9 · niveau 7

Pour chaque département, affiche le nombre d'employés payés au moins 45000 dans une colonne high et le nombre de ceux payés moins de 45000 dans une colonne low (colonnes : department, high, low).

Table staff (10 lignes)
idnamedepartmentsalarymanager_idhired
1AliceFinance52000NULL2015-03-01
2BobIT4100012018-06-15
3ClaireFinance3800012019-01-10
4DavidHR2900012020-09-01
5EmmaIT5000022017-11-20
6FaridIT4700022021-02-14
7GaelleHR3300042022-05-30
8HugoFinance4400032016-08-08
9IrisIT4700052023-01-09
10JulesFinance4400032024-03-18
Voir l’indice

Notions à utiliser : COUNT, SUM, AVG, MIN, MAX, GROUP BY, CASE.

Structure de la requête :

SELECT , SUM( >= ) AS , SUM( < ) AS 
FROM 
GROUP BY 
Voir la correction
SELECT department, SUM(salary >= 45000) AS high, SUM(salary < 45000) AS low
FROM staff
GROUP BY department;

Résultat attendu (3 lignes) :

departmenthighlow
Finance13
HR02
IT31

Exercice 10 · niveau 7

Affiche une ligne par décennie de sortie (2010 pour les années 2010 à 2019, 2020 pour 2020 à 2029), avec le nombre de films Drama dans une colonne drama et le nombre des autres films dans une colonne other (colonnes : decade, drama, other).

Table movies (10 lignes)
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
Voir l’indice

Notions à utiliser : COUNT, SUM, AVG, MIN, MAX, GROUP BY, CASE.

Structure de la requête :

SELECT ( / ) *  AS , SUM(CASE WHEN  =  THEN  ELSE  END) AS , SUM(CASE WHEN  <>  THEN  ELSE  END) AS 
FROM 
GROUP BY 
Voir la correction
SELECT (year / 10) * 10 AS decade, SUM(CASE WHEN genre = 'Drama' THEN 1 ELSE 0 END) AS drama, SUM(CASE WHEN genre <> 'Drama' THEN 1 ELSE 0 END) AS other
FROM movies
GROUP BY decade;

Résultat attendu (2 lignes) :

decadedramaother
201016
202021

Exercice 11 · niveau 7

Affiche une ligne par équipe ayant joué à domicile (colonnes : name, wins, draws, losses), avec son nombre de victoires, de nuls et de défaites à domicile.

Table teams (5 lignes)
idnamecityfounded
1Red FoxesLyon1950
2Blue OwlsParis1962
3Green BullsLille1971
4Gold HawksNantes1988
5Grey WolvesParis1990
Table matches (10 lignes)
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
Voir l’indice

Notions à utiliser : COUNT, SUM, AVG, MIN, MAX, GROUP BY, JOIN, CASE.

Structure de la requête :

SELECT , SUM(CASE WHEN  >  THEN  ELSE  END) AS , SUM(CASE WHEN  =  THEN  ELSE  END) AS , SUM(CASE WHEN  <  THEN  ELSE  END) AS 
FROM  
JOIN   ON  = 
GROUP BY 
Voir la correction
SELECT t.name, SUM(CASE WHEN m.home_goals > m.away_goals THEN 1 ELSE 0 END) AS wins, SUM(CASE WHEN m.home_goals = m.away_goals THEN 1 ELSE 0 END) AS draws, SUM(CASE WHEN m.home_goals < m.away_goals THEN 1 ELSE 0 END) AS losses
FROM teams t
JOIN matches m ON m.home_id = t.id
GROUP BY t.id;

Résultat attendu (5 lignes) :

namewinsdrawslosses
Red Foxes200
Blue Owls011
Green Bulls011
Gold Hawks110
Grey Wolves002

Exercice 12 · niveau 7

Affiche une ligne par jour de départ (colonnes : day, skyjet, airnova, bluewing) avec le nombre de vols de chaque compagnie ce jour-là (au format AAAA-MM-JJ pour day).

Table flights (12 lignes)
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
Voir l’indice

Notions à utiliser : COUNT, SUM, AVG, MIN, MAX, GROUP BY, CASE, Texte et dates.

Structure de la requête :

SELECT DATE() AS , SUM(CASE WHEN  =  THEN  ELSE  END) AS , SUM(CASE WHEN  =  THEN  ELSE  END) AS , SUM(CASE WHEN  =  THEN  ELSE  END) AS 
FROM 
GROUP BY 
Voir la correction
SELECT date(departs) AS day, SUM(CASE WHEN airline = 'SkyJet' THEN 1 ELSE 0 END) AS skyjet, SUM(CASE WHEN airline = 'AirNova' THEN 1 ELSE 0 END) AS airnova, SUM(CASE WHEN airline = 'BlueWing' THEN 1 ELSE 0 END) AS bluewing
FROM flights
GROUP BY day;

Résultat attendu (6 lignes) :

dayskyjetairnovabluewing
2025-06-01110
2025-06-02101
2025-06-03011
2025-06-04110
2025-06-05101
2025-06-06011

Exercice 13 · niveau 7

Pour chaque hôtel, affiche son nom et le nombre de chambres single, double et suite dans trois colonnes (0 s'il n'y en a pas).

Table hotels (5 lignes)
idnamecitystars
1Seaside InnNice3
2Alpine LodgeAnnecy4
3City LoftParis4
4Old MillBordeaux2
5Grand PalaceParis5
Table rooms (10 lignes)
idhotel_idtypeprice
11single70
21double95
32double130
42suite210
53single110
63double150
74double65
85double260
95suite480
105single190
Voir l’indice

Notions à utiliser : COUNT, SUM, AVG, MIN, MAX, GROUP BY, JOIN, CASE.

Structure de la requête :

SELECT , SUM(CASE WHEN  =  THEN  ELSE  END), SUM(CASE WHEN  =  THEN  ELSE  END), SUM(CASE WHEN  =  THEN  ELSE  END)
FROM  
LEFT JOIN   ON  = 
GROUP BY 
Voir la correction
SELECT h.name, SUM(CASE WHEN r.type = 'single' THEN 1 ELSE 0 END), SUM(CASE WHEN r.type = 'double' THEN 1 ELSE 0 END), SUM(CASE WHEN r.type = 'suite' THEN 1 ELSE 0 END)
FROM hotels h
LEFT JOIN rooms r ON r.hotel_id = h.id
GROUP BY h.id;

Résultat attendu (5 lignes) :

nameSUM(CASE WHEN r.type = 'single' THEN 1 ELSE 0 END)SUM(CASE WHEN r.type = 'double' THEN 1 ELSE 0 END)SUM(CASE WHEN r.type = 'suite' THEN 1 ELSE 0 END)
Seaside Inn110
Alpine Lodge011
City Loft110
Old Mill010
Grand Palace111

Exercice 14 · niveau 7

Pour chaque client qui a des commandes non annulées, affiche son nom et le montant dépensé en janvier, février et mars 2025 dans trois colonnes (0 si rien).

Table customers (6 lignes)
idnamecitysignup
1AlbaParis2024-01-10
2BorisLyon2024-02-15
3CarlaParis2024-03-01
4DenisNantes2024-05-20
5EvaLyon2024-06-30
6FabioLille2024-08-08
Table orders (8 lignes)
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
Table order_items (14 lignes)
order_idproduct_idqty
111
122
241
335
321
451
562
511
624
633
741
761
852
821
Table products (7 lignes)
idnamecategoryprice
1Desk LampHome35
2Coffee MugKitchen12
3NotebookOffice6
4Office ChairOffice149
5KettleKitchen45
6CushionHome22
7StaplerOffice9
Voir l’indice

Notions à utiliser : WHERE (filtres), COUNT, SUM, AVG, MIN, MAX, GROUP BY, JOIN, CASE, Texte et dates.

Structure de la requête :

SELECT , SUM(CASE WHEN  LIKE  THEN  *  ELSE  END), SUM(CASE WHEN  LIKE  THEN  *  ELSE  END), SUM(CASE WHEN  LIKE  THEN  *  ELSE  END)
FROM  
JOIN   ON  = 
JOIN   ON  = 
JOIN   ON  = 
WHERE  <> 
GROUP BY 
Voir la correction
SELECT c.name, SUM(CASE WHEN o.order_date LIKE '2025-01%' THEN oi.qty * p.price ELSE 0 END), SUM(CASE WHEN o.order_date LIKE '2025-02%' THEN oi.qty * p.price ELSE 0 END), SUM(CASE WHEN o.order_date LIKE '2025-03%' THEN oi.qty * p.price ELSE 0 END)
FROM customers c
JOIN orders o ON o.customer_id = c.id
JOIN order_items oi ON oi.order_id = o.id
JOIN products p ON p.id = oi.product_id
WHERE o.status <> 'cancelled'
GROUP BY c.id;

Résultat attendu (5 lignes) :

nameSUM(CASE WHEN o.order_date LIKE '2025-01%' THEN oi.qty * p.price ELSE 0 END)SUM(CASE WHEN o.order_date LIKE '2025-02%' THEN oi.qty * p.price ELSE 0 END)SUM(CASE WHEN o.order_date LIKE '2025-03%' THEN oi.qty * p.price ELSE 0 END)
Alba59420
Boris1490171
Carla00102
Denis0790
Eva0066

Exercice 15 · niveau 7

Pour chaque compte, affiche son numéro, son titulaire, le total des crédits, le total des débits (en positif) et le solde, dans des colonnes séparées (0 sans opération).

Table accounts (6 lignes)
idownercityopenedkind
1AliceParis2021-03-01current
2AliceParis2022-06-15savings
3BrunoLyon2020-09-10current
4ChloeLyon2023-01-20current
5DavidNice2019-11-05savings
6EmmaNice2024-04-01current
Table transactions (14 lignes)
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
Voir l’indice

Notions à utiliser : COUNT, SUM, AVG, MIN, MAX, GROUP BY, JOIN, CASE, NULL, COALESCE.

Structure de la requête :

SELECT , , COALESCE(SUM(CASE WHEN  >  THEN  END), ), COALESCE(-SUM(CASE WHEN  <  THEN  END), ), COALESCE(SUM(), )
FROM  
LEFT JOIN   ON  = 
GROUP BY 
Voir la correction
SELECT a.id, a.owner, COALESCE(SUM(CASE WHEN t.amount > 0 THEN t.amount END), 0), COALESCE(-SUM(CASE WHEN t.amount < 0 THEN t.amount END), 0), COALESCE(SUM(t.amount), 0)
FROM accounts a
LEFT JOIN transactions t ON t.account_id = a.id
GROUP BY a.id;

Résultat attendu (6 lignes) :

idownerCOALESCE(SUM(CASE WHEN t.amount > 0 THEN t.amount END), 0)COALESCE(-SUM(CASE WHEN t.amount < 0 THEN t.amount END), 0)COALESCE(SUM(t.amount), 0)
1Alice51009354165
2Alice100001000
3Bruno19001070830
4Chloe21006451455
5David30030
6Emma000

S’entraîner avec correction automatique

Dans SpeedQL, tu écris ta requête et elle est vérifiée tout de suite, sur ces tables puis sur un jeu de données caché.

S’entraîner sur les 25 questions « CASE »