Exercices SQL corrigés : UNION, INTERSECT, EXCEPT
Mis à jour le
UNION réunit deux résultats (sans doublon), INTERSECT garde ce qu’ils ont en commun, EXCEPT retire le second du premier. Ces 11 exercices vont du niveau 4 au niveau 4 ; ils utilisent la syntaxe de SQLite, le moteur SQL de SpeedQL.
Conseil : Les deux requêtes doivent renvoyer le même nombre de colonnes.
Relire la fiche « UNION, INTERSECT, EXCEPT » de l’aide-mémoire
Exercice 1
Affiche la liste, sans doublon, de tous les membres des deux clubs (tables chess et music). Utilise UNION.
| member |
|---|
| Alice |
| Bob |
| Claire |
| David |
| member |
|---|
| Claire |
| David |
| Emma |
| Farid |
Voir l’indice
Notions à utiliser : UNION, INTERSECT, EXCEPT.
Structure de la requête :
SELECT …
FROM …
UNION SELECT …
FROM …Voir la correction
SELECT member
FROM chess
UNION SELECT member
FROM music;Résultat attendu (6 lignes) :
| member |
|---|
| Alice |
| Bob |
| Claire |
| David |
| Emma |
| Farid |
Exercice 2
Affiche les membres inscrits aux deux clubs à la fois. Utilise INTERSECT.
| member |
|---|
| Alice |
| Bob |
| Claire |
| David |
| member |
|---|
| Claire |
| David |
| Emma |
| Farid |
Voir l’indice
Notions à utiliser : UNION, INTERSECT, EXCEPT.
Structure de la requête :
SELECT …
FROM …
INTERSECT SELECT …
FROM …Voir la correction
SELECT member
FROM chess
INTERSECT SELECT member
FROM music;Résultat attendu (2 lignes) :
| member |
|---|
| Claire |
| David |
Exercice 3
Affiche les membres du club chess qui ne sont pas dans le club music. Utilise EXCEPT.
| member |
|---|
| Alice |
| Bob |
| Claire |
| David |
| member |
|---|
| Claire |
| David |
| Emma |
| Farid |
Voir l’indice
Notions à utiliser : UNION, INTERSECT, EXCEPT.
Structure de la requête :
SELECT …
FROM …
EXCEPT SELECT …
FROM …Voir la correction
SELECT member
FROM chess
EXCEPT SELECT member
FROM music;Résultat attendu (2 lignes) :
| member |
|---|
| Alice |
| Bob |
Exercice 4
Affiche les genres dont tous les films ont une note d'au moins 7 : prends les genres qui ont un film noté au moins 7, sauf ceux qui ont un film noté moins de 7. Utilise EXCEPT.
| id | title | genre | year | duration | rating | director_id |
|---|---|---|---|---|---|---|
| 1 | Night Train | Thriller | 2015 | 118 | 7.8 | 1 |
| 2 | Blue Harbor | Drama | 2018 | 102 | 7.1 | 2 |
| 3 | Paper Moon City | Comedy | 2012 | 95 | 6.4 | 5 |
| 4 | Silent Peak | Drama | 2020 | 131 | 8.2 | 3 |
| 5 | Last Signal | Sci-Fi | 2019 | 142 | 7.5 | 1 |
| 6 | Summer Keys | Comedy | 2016 | 88 | 5.9 | 4 |
| 7 | Iron Garden | Sci-Fi | 2021 | 125 | 8 | 3 |
| 8 | Dust and Gold | Western | 2014 | 110 | 6.8 | 2 |
| 9 | The Quiet Hour | Drama | 2022 | 97 | 7.4 | 5 |
| 10 | Deep Current | Thriller | 2017 | 105 | 6.9 | NULL |
Voir l’indice
Notions à utiliser : WHERE (filtres), UNION, INTERSECT, EXCEPT.
Structure de la requête :
SELECT …
FROM …
WHERE … >= …
EXCEPT SELECT …
FROM …
WHERE … < …Voir la correction
SELECT genre
FROM movies
WHERE rating >= 7
EXCEPT SELECT genre
FROM movies
WHERE rating < 7;Résultat attendu (2 lignes) :
| genre |
|---|
| Drama |
| Sci-Fi |
Exercice 5
Affiche le titre des livres empruntés à la fois par un membre de Paris et par un membre de Lille. Utilise INTERSECT.
| id | title | author_id | genre | pages | year |
|---|---|---|---|---|---|
| 1 | Cold River | 1 | Novel | 320 | 2011 |
| 2 | Salt Roads | 2 | Travel | 210 | 2016 |
| 3 | The Glass Hive | 3 | Sci-Fi | 412 | 2019 |
| 4 | Winter Ledger | 1 | Crime | 288 | 2014 |
| 5 | Desert Letters | 2 | Novel | 356 | 2020 |
| 6 | Small Engines | 4 | Sci-Fi | 198 | 2022 |
| 7 | Harbor Lights | 5 | Novel | 445 | 2008 |
| 8 | Night Garden | 3 | Crime | 301 | 2017 |
| 9 | Paper Birds | 5 | Poetry | 96 | 2012 |
| 10 | Open Maps | 4 | Travel | 240 | 2021 |
| id | book_id | member_id | loan_date | return_date |
|---|---|---|---|---|
| 1 | 1 | 1 | 2025-01-05 | 2025-01-19 |
| 2 | 3 | 2 | 2025-01-10 | 2025-02-02 |
| 3 | 5 | 1 | 2025-02-01 | 2025-02-10 |
| 4 | 7 | 3 | 2025-02-03 | NULL |
| 5 | 3 | 4 | 2025-02-15 | 2025-03-01 |
| 6 | 2 | 2 | 2025-03-02 | 2025-03-30 |
| 7 | 8 | 5 | 2025-03-05 | NULL |
| 8 | 1 | 3 | 2025-03-10 | 2025-03-18 |
| 9 | 6 | 1 | 2025-03-20 | 2025-04-15 |
| 10 | 3 | 5 | 2025-04-01 | NULL |
| 11 | 9 | 4 | 2025-04-05 | 2025-04-12 |
| 12 | 10 | 2 | 2025-04-08 | 2025-04-20 |
| id | name | city | joined |
|---|---|---|---|
| 1 | Lena | Lyon | 2022-01-15 |
| 2 | Marc | Paris | 2021-06-03 |
| 3 | Nadia | Lyon | 2023-03-20 |
| 4 | Oscar | Lille | 2020-11-11 |
| 5 | Paula | Paris | 2024-02-01 |
| 6 | Quentin | Nantes | 2023-09-09 |
Voir l’indice
Notions à utiliser : WHERE (filtres), JOIN, UNION, INTERSECT, EXCEPT.
Structure de la requête :
SELECT …
FROM … …
JOIN … … ON … = …
JOIN … … ON … = …
WHERE … = …
INTERSECT SELECT …
FROM … …
JOIN … … ON … = …
JOIN … … ON … = …
WHERE … = …Voir la correction
SELECT b.title
FROM books b
JOIN loans l ON l.book_id = b.id
JOIN members m ON m.id = l.member_id
WHERE m.city = 'Paris'
INTERSECT SELECT b.title
FROM books b
JOIN loans l ON l.book_id = b.id
JOIN members m ON m.id = l.member_id
WHERE m.city = 'Lille';Résultat attendu (1 ligne) :
| title |
|---|
| The Glass Hive |
Exercice 6
Affiche, sans doublon, le nom des équipes qui ont gagné au moins un match, à domicile ou à l'extérieur. Utilise UNION.
| id | name | city | founded |
|---|---|---|---|
| 1 | Red Foxes | Lyon | 1950 |
| 2 | Blue Owls | Paris | 1962 |
| 3 | Green Bulls | Lille | 1971 |
| 4 | Gold Hawks | Nantes | 1988 |
| 5 | Grey Wolves | Paris | 1990 |
| id | played_on | home_id | away_id | home_goals | away_goals |
|---|---|---|---|---|---|
| 1 | 2025-08-02 | 1 | 2 | 2 | 1 |
| 2 | 2025-08-03 | 3 | 4 | 0 | 0 |
| 3 | 2025-08-09 | 5 | 1 | 1 | 3 |
| 4 | 2025-08-10 | 2 | 3 | 2 | 2 |
| 5 | 2025-08-16 | 4 | 5 | 3 | 1 |
| 6 | 2025-08-17 | 1 | 3 | 1 | 0 |
| 7 | 2025-08-23 | 2 | 4 | 0 | 1 |
| 8 | 2025-08-24 | 3 | 5 | 2 | 3 |
| 9 | 2025-08-30 | 4 | 1 | 1 | 1 |
| 10 | 2025-08-31 | 5 | 2 | 0 | 2 |
Voir l’indice
Notions à utiliser : WHERE (filtres), JOIN, UNION, INTERSECT, EXCEPT.
Structure de la requête :
SELECT …
FROM … …
JOIN … … ON … = …
WHERE … > …
UNION SELECT …
FROM … …
JOIN … … ON … = …
WHERE … > …Voir la correction
SELECT t.name
FROM teams t
JOIN matches m ON m.home_id = t.id
WHERE m.home_goals > m.away_goals
UNION SELECT t.name
FROM teams t
JOIN matches m ON m.away_id = t.id
WHERE m.away_goals > m.home_goals;Résultat attendu (4 lignes) :
| name |
|---|
| Blue Owls |
| Gold Hawks |
| Grey Wolves |
| Red Foxes |
Exercice 7
Affiche les villes d'arrivée desservies à la fois par SkyJet et par AirNova. Utilise INTERSECT.
| id | airline | origin | dest | departs | duration_min | price | seats_sold | capacity |
|---|---|---|---|---|---|---|---|---|
| 1 | SkyJet | CDG | MAD | 2025-06-01 08:10 | 125 | 89 | 150 | 180 |
| 2 | AirNova | CDG | LIS | 2025-06-01 11:40 | 155 | 120 | 160 | 170 |
| 3 | BlueWing | LYS | FCO | 2025-06-02 07:30 | 95 | 75 | 110 | 150 |
| 4 | SkyJet | MAD | CDG | 2025-06-02 18:20 | 120 | 95 | 170 | 180 |
| 5 | AirNova | BER | CDG | 2025-06-03 09:05 | 110 | 105 | 140 | 160 |
| 6 | BlueWing | NCE | BER | 2025-06-03 13:50 | 130 | 140 | 90 | 150 |
| 7 | SkyJet | CDG | FCO | 2025-06-04 06:45 | 135 | 99 | 175 | 180 |
| 8 | AirNova | LIS | MAD | 2025-06-04 16:15 | 75 | 65 | 60 | 120 |
| 9 | BlueWing | FCO | LYS | 2025-06-05 20:30 | 100 | 82 | 130 | 150 |
| 10 | SkyJet | CDG | BER | 2025-06-05 10:00 | 105 | 110 | 120 | 180 |
| 11 | AirNova | MAD | LIS | 2025-06-06 12:25 | 80 | 70 | 95 | 120 |
| 12 | BlueWing | LYS | MAD | 2025-06-06 15:40 | 115 | 79 | 100 | 150 |
| code | city | country |
|---|---|---|
| CDG | Paris | France |
| LYS | Lyon | France |
| MAD | Madrid | Spain |
| LIS | Lisbon | Portugal |
| FCO | Rome | Italy |
| BER | Berlin | Germany |
| NCE | Nice | France |
Voir l’indice
Notions à utiliser : WHERE (filtres), JOIN, UNION, INTERSECT, EXCEPT.
Structure de la requête :
SELECT …
FROM … …
JOIN … … ON … = …
WHERE … = …
INTERSECT SELECT …
FROM … …
JOIN … … ON … = …
WHERE … = …Voir la correction
SELECT a.city
FROM flights f
JOIN airports a ON a.code = f.dest
WHERE f.airline = 'SkyJet'
INTERSECT SELECT a.city
FROM flights f
JOIN airports a ON a.code = f.dest
WHERE f.airline = 'AirNova';Résultat attendu (2 lignes) :
| city |
|---|
| Madrid |
| Paris |
Exercice 8
Affiche les jours où il a plu à la fois à Paris et à Lyon. Utilise INTERSECT.
| id | city | day | temp_max | temp_min | rain_mm |
|---|---|---|---|---|---|
| 1 | Paris | 2025-07-01 | 24 | 15 | 0 |
| 2 | Paris | 2025-07-02 | 27 | 17 | 0 |
| 3 | Paris | 2025-07-03 | 22 | 16 | 4.5 |
| 4 | Paris | 2025-07-04 | 19 | 14 | 12 |
| 5 | Paris | 2025-07-05 | 23 | 13 | 0 |
| 6 | Lyon | 2025-07-01 | 26 | 16 | 0 |
| 7 | Lyon | 2025-07-02 | 29 | 18 | 0 |
| 8 | Lyon | 2025-07-03 | 31 | 19 | 0 |
| 9 | Lyon | 2025-07-04 | 24 | 17 | 8.5 |
| 10 | Lyon | 2025-07-05 | 22 | 15 | 3 |
| 11 | Marseille | 2025-07-01 | 30 | 21 | 0 |
| 12 | Marseille | 2025-07-02 | 32 | 22 | 0 |
| 13 | Marseille | 2025-07-03 | 33 | 23 | 0 |
| 14 | Marseille | 2025-07-04 | 29 | 21 | 0 |
| 15 | Marseille | 2025-07-05 | 28 | 20 | 0 |
Voir l’indice
Notions à utiliser : WHERE (filtres), UNION, INTERSECT, EXCEPT.
Structure de la requête :
SELECT …
FROM …
WHERE … = … AND … > …
INTERSECT SELECT …
FROM …
WHERE … = … AND … > …Voir la correction
SELECT day
FROM readings
WHERE city = 'Paris' AND rain_mm > 0
INTERSECT SELECT day
FROM readings
WHERE city = 'Lyon' AND rain_mm > 0;Résultat attendu (1 ligne) :
| day |
|---|
| 2025-07-04 |
Exercice 9
Avec EXCEPT, affiche les pays des clients, sauf ceux des clients qui ont séjourné dans un hôtel de Paris.
| id | name | country |
|---|---|---|
| 1 | Ana Silva | Portugal |
| 2 | Ben Ford | USA |
| 3 | Chen Li | China |
| 4 | Dana Weiss | Germany |
| 5 | Emma Roy | France |
| 6 | Farid Nasser | Morocco |
| id | room_id | guest_id | check_in | check_out |
|---|---|---|---|---|
| 1 | 2 | 1 | 2025-07-01 | 2025-07-04 |
| 2 | 5 | 2 | 2025-07-02 | 2025-07-05 |
| 3 | 8 | 3 | 2025-07-03 | 2025-07-06 |
| 4 | 3 | 4 | 2025-07-05 | 2025-07-12 |
| 5 | 6 | 5 | 2025-07-06 | 2025-07-08 |
| 6 | 1 | 2 | 2025-07-08 | 2025-07-10 |
| 7 | 9 | 3 | 2025-07-10 | 2025-07-11 |
| 8 | 7 | 5 | 2025-07-11 | 2025-07-15 |
| 9 | 4 | 1 | 2025-07-14 | 2025-07-16 |
| 10 | 6 | 4 | 2025-07-15 | 2025-07-19 |
| 11 | 6 | 5 | 2025-07-16 | 2025-07-18 |
| id | hotel_id | type | price |
|---|---|---|---|
| 1 | 1 | single | 70 |
| 2 | 1 | double | 95 |
| 3 | 2 | double | 130 |
| 4 | 2 | suite | 210 |
| 5 | 3 | single | 110 |
| 6 | 3 | double | 150 |
| 7 | 4 | double | 65 |
| 8 | 5 | double | 260 |
| 9 | 5 | suite | 480 |
| 10 | 5 | single | 190 |
| id | name | city | stars |
|---|---|---|---|
| 1 | Seaside Inn | Nice | 3 |
| 2 | Alpine Lodge | Annecy | 4 |
| 3 | City Loft | Paris | 4 |
| 4 | Old Mill | Bordeaux | 2 |
| 5 | Grand Palace | Paris | 5 |
Voir l’indice
Notions à utiliser : WHERE (filtres), JOIN, UNION, INTERSECT, EXCEPT.
Structure de la requête :
SELECT …
FROM …
EXCEPT SELECT …
FROM … …
JOIN … … ON … = …
JOIN … … ON … = …
JOIN … … ON … = …
WHERE … = …Voir la correction
SELECT country
FROM guests
EXCEPT SELECT g.country
FROM guests g
JOIN bookings b ON b.guest_id = g.id
JOIN rooms r ON r.id = b.room_id
JOIN hotels h ON h.id = r.hotel_id
WHERE h.city = 'Paris';Résultat attendu (2 lignes) :
| country |
|---|
| Morocco |
| Portugal |
Exercice 10
Avec INTERSECT, affiche le nom des clients qui ont commandé à la fois un produit Office et un produit Kitchen.
| id | name | city | signup |
|---|---|---|---|
| 1 | Alba | Paris | 2024-01-10 |
| 2 | Boris | Lyon | 2024-02-15 |
| 3 | Carla | Paris | 2024-03-01 |
| 4 | Denis | Nantes | 2024-05-20 |
| 5 | Eva | Lyon | 2024-06-30 |
| 6 | Fabio | Lille | 2024-08-08 |
| id | customer_id | order_date | status |
|---|---|---|---|
| 1 | 1 | 2025-01-05 | shipped |
| 2 | 2 | 2025-01-12 | shipped |
| 3 | 1 | 2025-02-03 | paid |
| 4 | 3 | 2025-02-10 | cancelled |
| 5 | 4 | 2025-02-20 | shipped |
| 6 | 5 | 2025-03-02 | shipped |
| 7 | 2 | 2025-03-15 | paid |
| 8 | 3 | 2025-03-28 | shipped |
| order_id | product_id | qty |
|---|---|---|
| 1 | 1 | 1 |
| 1 | 2 | 2 |
| 2 | 4 | 1 |
| 3 | 3 | 5 |
| 3 | 2 | 1 |
| 4 | 5 | 1 |
| 5 | 6 | 2 |
| 5 | 1 | 1 |
| 6 | 2 | 4 |
| 6 | 3 | 3 |
| 7 | 4 | 1 |
| 7 | 6 | 1 |
| 8 | 5 | 2 |
| 8 | 2 | 1 |
| id | name | category | price |
|---|---|---|---|
| 1 | Desk Lamp | Home | 35 |
| 2 | Coffee Mug | Kitchen | 12 |
| 3 | Notebook | Office | 6 |
| 4 | Office Chair | Office | 149 |
| 5 | Kettle | Kitchen | 45 |
| 6 | Cushion | Home | 22 |
| 7 | Stapler | Office | 9 |
Voir l’indice
Notions à utiliser : WHERE (filtres), JOIN, UNION, INTERSECT, EXCEPT.
Structure de la requête :
SELECT …
FROM … …
JOIN … … ON … = …
JOIN … … ON … = …
JOIN … … ON … = …
WHERE … = …
INTERSECT SELECT …
FROM … …
JOIN … … ON … = …
JOIN … … ON … = …
JOIN … … ON … = …
WHERE … = …Voir la correction
SELECT c.name
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 p.category = 'Office'
INTERSECT SELECT c.name
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 p.category = 'Kitchen';Résultat attendu (2 lignes) :
| name |
|---|
| Alba |
| Eva |
Exercice 11
Avec UNION, affiche sans doublon les titulaires qui ont reçu un salaire (label 'salary') et ceux qui ont un compte épargne (kind 'savings').
| id | owner | city | opened | kind |
|---|---|---|---|---|
| 1 | Alice | Paris | 2021-03-01 | current |
| 2 | Alice | Paris | 2022-06-15 | savings |
| 3 | Bruno | Lyon | 2020-09-10 | current |
| 4 | Chloe | Lyon | 2023-01-20 | current |
| 5 | David | Nice | 2019-11-05 | savings |
| 6 | Emma | Nice | 2024-04-01 | current |
| id | account_id | made_on | amount | label |
|---|---|---|---|---|
| 1 | 1 | 2025-01-02 | 2500 | salary |
| 2 | 1 | 2025-01-05 | -60 | groceries |
| 3 | 1 | 2025-01-12 | -800 | rent |
| 4 | 2 | 2025-01-15 | 500 | transfer |
| 5 | 3 | 2025-01-03 | 1900 | salary |
| 6 | 3 | 2025-01-20 | -120 | groceries |
| 7 | 3 | 2025-02-01 | -950 | rent |
| 8 | 4 | 2025-01-25 | 2100 | salary |
| 9 | 4 | 2025-02-03 | -45 | restaurant |
| 10 | 1 | 2025-02-02 | 2600 | salary |
| 11 | 1 | 2025-02-06 | -75 | groceries |
| 12 | 5 | 2025-02-10 | 30 | interest |
| 13 | 2 | 2025-02-15 | 500 | transfer |
| 14 | 4 | 2025-02-18 | -600 | rent |
Voir l’indice
Notions à utiliser : WHERE (filtres), JOIN, UNION, INTERSECT, EXCEPT.
Structure de la requête :
SELECT …
FROM … …
JOIN … … ON … = …
WHERE … = …
UNION SELECT …
FROM …
WHERE … = …Voir la correction
SELECT a.owner
FROM accounts a
JOIN transactions t ON t.account_id = a.id
WHERE t.label = 'salary'
UNION SELECT owner
FROM accounts
WHERE kind = 'savings';Résultat attendu (4 lignes) :
| owner |
|---|
| Alice |
| Bruno |
| Chloe |
| David |
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 13 questions « UNION, INTERSECT, EXCEPT »