Exercices SQL corrigés : les CTE (WITH)

Exercices SQL corrigés : les CTE (WITH)

Mis à jour le

WITH donne un nom à une requête intermédiaire, qu’on réutilise ensuite comme une table. Ces 15 exercices vont du niveau 5 au niveau 8 ; ils utilisent la syntaxe de SQLite, le moteur SQL de SpeedQL.

Conseil : Plusieurs CTE se suivent, séparées par des virgules, avant le SELECT final.

Relire la fiche « CTE (WITH) » de l’aide-mémoire

Exercice 1 · niveau 5

Avec une CTE (WITH), calcule le salaire moyen de chaque département, puis affiche les départements dont la moyenne dépasse 45000.

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 : WHERE (filtres), COUNT, SUM, AVG, MIN, MAX, GROUP BY, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT , AVG() AS 
  FROM 
  GROUP BY )
SELECT 
FROM 
WHERE  > 
Voir la correction
WITH avg_dept AS (
  SELECT department, AVG(salary) AS a
  FROM staff
  GROUP BY department)
SELECT department
FROM avg_dept
WHERE a > 45000;

Résultat attendu (1 ligne) :

department
IT

Exercice 2 · niveau 5

Avec une CTE (WITH), calcule le total des salaires par département, puis affiche le département dont le total est le plus élevé.

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 : ORDER BY, LIMIT, COUNT, SUM, AVG, MIN, MAX, GROUP BY, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT , SUM() AS 
  FROM 
  GROUP BY )
SELECT 
FROM 
ORDER BY  DESC
LIMIT 
Voir la correction
WITH t AS (
  SELECT department, SUM(salary) AS s
  FROM staff
  GROUP BY department)
SELECT department
FROM t
ORDER BY s DESC
LIMIT 1;

Résultat attendu (1 ligne) :

department
IT

Exercice 3 · niveau 5

Avec une CTE (WITH), compte les emprunts de chaque membre, puis affiche le nom des membres qui ont emprunté plus que la moyenne (moyenne calculée sur les membres qui ont au moins un emprunt).

Table members (6 lignes)
idnamecityjoined
1LenaLyon2022-01-15
2MarcParis2021-06-03
3NadiaLyon2023-03-20
4OscarLille2020-11-11
5PaulaParis2024-02-01
6QuentinNantes2023-09-09
Table loans (12 lignes)
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
Voir l’indice

Notions à utiliser : WHERE (filtres), COUNT, SUM, AVG, MIN, MAX, GROUP BY, JOIN, Sous-requêtes, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT , COUNT(*) AS 
  FROM 
  GROUP BY )
SELECT 
FROM 
JOIN   ON  = 
WHERE  > (SELECT AVG() FROM )
Voir la correction
WITH c AS (
  SELECT member_id, COUNT(*) AS n
  FROM loans
  GROUP BY member_id)
SELECT m.name
FROM c
JOIN members m ON m.id = c.member_id
WHERE c.n > (SELECT AVG(n) FROM c);

Résultat attendu (2 lignes) :

name
Lena
Marc

Exercice 4 · niveau 5

Avec une CTE (WITH), calcule le nombre total de buts de chaque match, puis affiche la date des matchs dont le total dépasse la moyenne des totaux.

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 : WHERE (filtres), COUNT, SUM, AVG, MIN, MAX, Sous-requêtes, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT ,  +  AS 
  FROM )
SELECT 
FROM 
WHERE  > (SELECT AVG() FROM )
Voir la correction
WITH t AS (
  SELECT played_on, home_goals + away_goals AS g
  FROM matches)
SELECT played_on
FROM t
WHERE g > (SELECT AVG(g) FROM t);

Résultat attendu (5 lignes) :

played_on
2025-08-02
2025-08-09
2025-08-10
2025-08-16
2025-08-24

Exercice 5 · niveau 5

Avec une CTE (WITH), calcule la température moyenne de chaque relevé ((max + min) / 2), puis affiche la ville, le jour et cette moyenne pour les relevés où elle dépasse 22.

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

Notions à utiliser : WHERE (filtres), CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT , , ( + ) /  AS 
  FROM )
SELECT , , 
FROM 
WHERE  > 
Voir la correction
WITH m AS (
  SELECT city, day, (temp_max + temp_min) / 2.0 AS t
  FROM readings)
SELECT city, day, t
FROM m
WHERE t > 22;

Résultat attendu (7 lignes) :

citydayt
Lyon2025-07-0223.5
Lyon2025-07-0325
Marseille2025-07-0125.5
Marseille2025-07-0227
Marseille2025-07-0328
Marseille2025-07-0425
Marseille2025-07-0524

Exercice 6 · niveau 5

Avec une CTE (WITH), calcule le montant de chaque réservation (nombre de nuits × prix de la chambre), puis affiche le numéro et le montant des réservations de plus de 500.

Table rooms (10 lignes)
idhotel_idtypeprice
11single70
21double95
32double130
42suite210
53single110
63double150
74double65
85double260
95suite480
105single190
Table bookings (11 lignes)
idroom_idguest_idcheck_incheck_out
1212025-07-012025-07-04
2522025-07-022025-07-05
3832025-07-032025-07-06
4342025-07-052025-07-12
5652025-07-062025-07-08
6122025-07-082025-07-10
7932025-07-102025-07-11
8752025-07-112025-07-15
9412025-07-142025-07-16
10642025-07-152025-07-19
11652025-07-162025-07-18
Voir l’indice

Notions à utiliser : WHERE (filtres), JOIN, Texte et dates, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT , (JULIANDAY() - JULIANDAY()) *  AS 
  FROM  
  JOIN   ON  = )
SELECT , CAST( AS INTEGER)
FROM 
WHERE  > 
Voir la correction
WITH a AS (
  SELECT b.id, (julianday(b.check_out) - julianday(b.check_in)) * r.price AS amount
  FROM bookings b
  JOIN rooms r ON r.id = b.room_id)
SELECT id, CAST(amount AS INTEGER)
FROM a
WHERE amount > 500;

Résultat attendu (3 lignes) :

idCAST(amount AS INTEGER)
3780
4910
10600

Exercice 7 · niveau 5

Avec une CTE (WITH), calcule le coût de chaque projet (somme des heures × taux du développeur), puis affiche le nom et le coût des projets dont le coût dépasse 15 % du budget.

Table projects (4 lignes)
idnameclientbudgetdeadline
1AtlasAcme200002025-06-30
2BeaconBolt120002025-05-15
3CometAcme80002025-04-30
4DeltaCyan150002025-07-31
Table tasks (10 lignes)
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
Table devs (6 lignes)
idnameteamrate
1AnaWeb55
2BoWeb48
3CleoData62
4DanData58
5EveOps50
6FinnOps45
Voir l’indice

Notions à utiliser : WHERE (filtres), COUNT, SUM, AVG, MIN, MAX, GROUP BY, JOIN, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT , SUM( * ) AS 
  FROM  
  JOIN   ON  = 
  GROUP BY )
SELECT , 
FROM  
JOIN  ON  = 
WHERE  >  * 
Voir la correction
WITH c AS (
  SELECT t.project_id, SUM(t.hours * d.rate) AS cost
  FROM tasks t
  JOIN devs d ON d.id = t.dev_id
  GROUP BY t.project_id)
SELECT p.name, c.cost
FROM projects p
JOIN c ON c.project_id = p.id
WHERE c.cost > 0.15 * p.budget;

Résultat attendu (2 lignes) :

namecost
Comet1390
Delta2590

Exercice 8 · niveau 5

Avec une CTE (WITH), calcule pour chaque titulaire le salaire reçu en janvier et en février 2025, puis affiche le nom et les deux montants des titulaires dont le salaire de février dépasse celui de janvier.

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 : WHERE (filtres), COUNT, SUM, AVG, MIN, MAX, GROUP BY, JOIN, CASE, Texte et dates, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT , SUM(CASE WHEN  LIKE  THEN  ELSE  END) AS , SUM(CASE WHEN  LIKE  THEN  ELSE  END) AS 
  FROM  
  JOIN   ON  = 
  WHERE  = 
  GROUP BY )
SELECT , , 
FROM 
WHERE  > 
Voir la correction
WITH s AS (
  SELECT a.owner, SUM(CASE WHEN t.made_on LIKE '2025-01%' THEN t.amount ELSE 0 END) AS jan, SUM(CASE WHEN t.made_on LIKE '2025-02%' THEN t.amount ELSE 0 END) AS feb
  FROM accounts a
  JOIN transactions t ON t.account_id = a.id
  WHERE t.label = 'salary'
  GROUP BY a.owner)
SELECT owner, jan, feb
FROM s
WHERE feb > jan;

Résultat attendu (1 ligne) :

ownerjanfeb
Alice25002600

Exercice 9 · niveau 7

Pour chaque catégorie, affiche la catégorie, le nom du produit le plus vendu en quantité et cette quantité (en cas d'égalité, tous les produits ex æquo).

Table products (7 lignes)
idnamecategoryprice
1Desk LampHome35
2Coffee MugKitchen12
3NotebookOffice6
4Office ChairOffice149
5KettleKitchen45
6CushionHome22
7StaplerOffice9
Table order_items (14 lignes)
order_idproduct_idqty
111
122
241
335
321
451
562
511
624
633
741
761
852
821
Voir l’indice

Notions à utiliser : WHERE (filtres), COUNT, SUM, AVG, MIN, MAX, GROUP BY, JOIN, Sous-requêtes, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT , , SUM() AS 
  FROM  
  JOIN   ON  = 
  GROUP BY )
SELECT , , 
FROM 
WHERE  = (SELECT MAX() FROM   WHERE  = )
Voir la correction
WITH q AS (
  SELECT p.category, p.name, SUM(oi.qty) AS s
  FROM products p
  JOIN order_items oi ON oi.product_id = p.id
  GROUP BY p.id)
SELECT category, name, s
FROM q
WHERE s = (SELECT MAX(s) FROM q q2 WHERE q2.category = q.category);

Résultat attendu (3 lignes) :

categorynames
KitchenCoffee Mug8
OfficeNotebook8
HomeCushion3

Exercice 10 · niveau 8

Avec une CTE (WITH), calcule le total facturé par client, puis affiche client, ce total et une colonne size valant 'big' si le total est d'au moins 1500, sinon 'small'. 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 : COUNT, SUM, AVG, MIN, MAX, GROUP BY, CASE, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT , SUM() AS 
  FROM 
  GROUP BY )
SELECT , , CASE WHEN  >=  THEN  ELSE  END AS 
FROM 
Voir la correction
WITH t AS (
  SELECT client, SUM(amount) AS total
  FROM invoices
  GROUP BY client)
SELECT client, total, CASE WHEN total >= 1500 THEN 'big' ELSE 'small' END AS size
FROM t;

Résultat attendu (3 lignes) :

clienttotalsize
Acme2000big
Bolt1400small
Cyan900small

Exercice 11 · niveau 8

Avec une CTE (WITH), calcule les points de chaque équipe sur tous ses matchs, à domicile et à l'extérieur (victoire 3 points, nul 1 point, défaite 0), puis affiche le nom de l'équipe et son total de points, du plus grand total au plus petit (en cas d'égalité, par ordre alphabétique du nom).

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 : ORDER BY, LIMIT, COUNT, SUM, AVG, MIN, MAX, GROUP BY, JOIN, CASE, UNION, INTERSECT, EXCEPT, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT  AS , CASE WHEN  >  THEN  WHEN  =  THEN  ELSE  END AS 
  FROM 
  UNION ALL SELECT , CASE WHEN  >  THEN  WHEN  =  THEN  ELSE  END
  FROM )
SELECT , SUM()
FROM 
JOIN   ON  = 
GROUP BY 
ORDER BY SUM() DESC, 
Voir la correction
WITH r AS (
  SELECT home_id AS team, CASE WHEN home_goals > away_goals THEN 3 WHEN home_goals = away_goals THEN 1 ELSE 0 END AS pts
  FROM matches
  UNION ALL SELECT away_id, CASE WHEN away_goals > home_goals THEN 3 WHEN away_goals = home_goals THEN 1 ELSE 0 END
  FROM matches)
SELECT t.name, SUM(r.pts)
FROM r
JOIN teams t ON t.id = r.team
GROUP BY t.id
ORDER BY SUM(r.pts) DESC, t.name;

Résultat attendu (5 lignes, dans cet ordre) :

nameSUM(r.pts)
Red Foxes10
Gold Hawks8
Blue Owls4
Grey Wolves3
Green Bulls2

Exercice 12 · niveau 8

Avec une CTE (WITH), calcule le taux de remplissage de chaque vol (places vendues / capacité, en %), puis affiche pour chaque compagnie son taux moyen arrondi à 1 décimale et le nombre de ses vols remplis à plus de 80 %.

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, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT ,  *  /  AS 
  FROM )
SELECT , ROUND(AVG(), ), SUM(CASE WHEN  >  THEN  ELSE  END)
FROM 
GROUP BY 
Voir la correction
WITH r AS (
  SELECT airline, 100.0 * seats_sold / capacity AS t
  FROM flights)
SELECT airline, ROUND(AVG(t), 1), SUM(CASE WHEN t > 80 THEN 1 ELSE 0 END)
FROM r
GROUP BY airline;

Résultat attendu (3 lignes) :

airlineROUND(AVG(t), 1)SUM(CASE WHEN t > 80 THEN 1 ELSE 0 END)
AirNova77.72
BlueWing71.71
SkyJet85.43

Exercice 13 · niveau 8

Avec une CTE (WITH), calcule pour chaque jour la moyenne des températures maximales de toutes les villes, puis affiche le jour, la ville et l'écart (arrondi à 1 décimale) des relevés qui dépassent cette moyenne de plus de 3 degrés.

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

Notions à utiliser : WHERE (filtres), COUNT, SUM, AVG, MIN, MAX, GROUP BY, JOIN, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT , AVG() AS 
  FROM 
  GROUP BY )
SELECT , , ROUND( - , )
FROM  
JOIN  ON  = 
WHERE  -  > 
Voir la correction
WITH a AS (
  SELECT day, AVG(temp_max) AS m
  FROM readings
  GROUP BY day)
SELECT r.day, r.city, ROUND(r.temp_max - a.m, 1)
FROM readings r
JOIN a ON a.day = r.day
WHERE r.temp_max - a.m > 3;

Résultat attendu (4 lignes) :

daycityROUND(r.temp_max - a.m, 1)
2025-07-01Marseille3.3
2025-07-03Marseille4.3
2025-07-04Marseille5
2025-07-05Marseille3.7

Exercice 14 · niveau 8

Pour chaque projet, affiche son nom, son budget, son coût (heures × taux, 0 sans tâche), le budget restant et la part du budget consommée en % arrondie à 1 décimale, de la plus forte part à la plus faible (en cas d'égalité, par nom).

Table projects (4 lignes)
idnameclientbudgetdeadline
1AtlasAcme200002025-06-30
2BeaconBolt120002025-05-15
3CometAcme80002025-04-30
4DeltaCyan150002025-07-31
Table tasks (10 lignes)
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
Table devs (6 lignes)
idnameteamrate
1AnaWeb55
2BoWeb48
3CleoData62
4DanData58
5EveOps50
6FinnOps45
Voir l’indice

Notions à utiliser : ORDER BY, LIMIT, COUNT, SUM, AVG, MIN, MAX, GROUP BY, JOIN, NULL, COALESCE, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT , , , COALESCE(SUM( * ), ) AS 
  FROM  
  LEFT JOIN   ON  = 
  LEFT JOIN   ON  = 
  GROUP BY )
SELECT , , ,  - , ROUND( *  / , )
FROM 
ORDER BY  *  /  DESC, 
Voir la correction
WITH c AS (
  SELECT p.id, p.name, p.budget, COALESCE(SUM(t.hours * d.rate), 0) AS cost
  FROM projects p
  LEFT JOIN tasks t ON t.project_id = p.id
  LEFT JOIN devs d ON d.id = t.dev_id
  GROUP BY p.id)
SELECT name, budget, cost, budget - cost, ROUND(100.0 * cost / budget, 1)
FROM c
ORDER BY 1.0 * cost / budget DESC, name;

Résultat attendu (4 lignes, dans cet ordre) :

namebudgetcostbudget - costROUND(100.0 * cost / budget, 1)
Comet80001390661017.4
Delta1500025901241017.3
Atlas2000022841771611.4
Beacon1200012281077210.2

Exercice 15 · niveau 8

Affiche le nom des titulaires dont les dépenses dépassent 30 % de leurs revenus (tous comptes confondus), avec ce ratio en % arrondi à 1 décimale.

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 : WHERE (filtres), COUNT, SUM, AVG, MIN, MAX, GROUP BY, JOIN, CASE, CTE (WITH).

Structure de la requête :

WITH  AS (
  SELECT , SUM(CASE WHEN  >  THEN  ELSE  END) AS , -SUM(CASE WHEN  <  THEN  ELSE  END) AS 
  FROM  
  JOIN   ON  = 
  GROUP BY )
SELECT , ROUND( *  / , )
FROM 
WHERE  >  AND  >  * 
Voir la correction
WITH s AS (
  SELECT a.owner, SUM(CASE WHEN t.amount > 0 THEN t.amount ELSE 0 END) AS income, -SUM(CASE WHEN t.amount < 0 THEN t.amount ELSE 0 END) AS spent
  FROM accounts a
  JOIN transactions t ON t.account_id = a.id
  GROUP BY a.owner)
SELECT owner, ROUND(100.0 * spent / income, 1)
FROM s
WHERE income > 0 AND spent > 0.3 * income;

Résultat attendu (2 lignes) :

ownerROUND(100.0 * spent / income, 1)
Bruno56.3
Chloe30.7

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 31 questions « CTE (WITH) »