Écrire du SQL · Chapitre 7
Ajouter des conditions
Jusqu'ici, nos requêtes renvoyaient toutes les lignes d'une table. En pratique, on cherche presque toujours un sous-ensemble : les ventes d'un client, les produits d'une catégorie, les commandes d'un mois. Filtrer les lignes rend le résultat lisible, et la requête plus rapide, puisque la base traite moins de données.
Après SELECT, FROM, DISTINCT et AS, voici la clause WHERE.
WHERE
WHERE garde uniquement les lignes qui respectent une condition. Elle s'écrit après FROM :
SELECT CustomerID, ProductID, "NOS (COPA)", Date
FROM perform21
WHERE Date = '2021-08-01'Cette requête affiche les ventes du mois d'août 2021 (dans les tables perform, chaque mois est daté de son premier jour).
Les opérateurs de comparaison
| Opérateur | Signification | Exemple |
|---|---|---|
= |
égal à | WHERE Category = 'Capsules' |
<> ou != |
différent de | WHERE Status <> 'Discontinued' |
<, <= |
inférieur (ou égal) à | WHERE "NOS (COPA)" < 0 |
>, >= |
supérieur (ou égal) à | WHERE Intensity >= 10 |
BETWEEN … AND … |
compris entre deux bornes incluses | WHERE Date BETWEEN '2021-09-01' AND '2021-12-01' |
IN (…) |
égal à l'une des valeurs de la liste | WHERE Channel IN ('E-commerce', 'Export') |
LIKE |
correspond à un motif de texte | WHERE CustomerName LIKE 'D%' |
IS NULL |
la valeur est absente | WHERE SubCategory IS NULL |
IS NOT NULL |
la valeur est renseignée | WHERE SubCategory IS NOT NULL |
AND |
les deux conditions sont vraies | WHERE condition1 AND condition2 |
OR |
au moins une condition est vraie | WHERE condition1 OR condition2 |
NOT |
inverse la condition | WHERE NOT Category = 'Others' |
Question 7.1
Affiche toutes les colonnes des ventes de perform24 qui sont des retours de marchandise, c'est-à-dire dont le chiffre d'affaires "NOS (COPA)" est négatif.
Ta réponse
-- Question 7.1 : écris ta requête ici
SELECT Voir la solution
SELECT *
FROM perform24
WHERE "NOS (COPA)" < 0Le nom de la colonne contient un espace et des parenthèses : il faut l'écrire entre guillemets doubles. Un chiffre d'affaires négatif correspond à un avoir : le client a rendu de la marchandise. Ces lignes existent dans toutes les entreprises et faussent les moyennes si on les oublie.
LIKE : chercher dans du texte
LIKE compare une valeur à un motif, un peu comme la recherche Ctrl + F d'un navigateur. Deux caractères spéciaux composent le motif :
%remplace n'importe quelle suite de caractères, y compris aucun ;_remplace exactement un caractère.
| Motif | Trouve les valeurs qui… |
|---|---|
'A%' |
commencent par A |
'%A' |
finissent par A |
'%A%' |
contiennent un A |
'_A%' |
ont un A en deuxième position |
Prenons une table fictive utilisateurs :
| ID | Nom | Age | Ville |
|---|---|---|---|
| 1 | Alice | 28 | Paris |
| 2 | Bob | 34 | New York |
| 3 | Charlie | 22 | Berlin |
| 7 | Amaury | 23 | Milan |
SELECT *
FROM utilisateurs
WHERE Nom LIKE 'A%'Cette requête renvoie Alice et Amaury, les deux noms qui commencent par A.
Sur nos données, cette requête cherche les clients dont le nom finit par S :
SELECT CustomerID, CustomerName, StrategicCustomer
FROM customer
WHERE CustomerName LIKE '%S'Question 7.2
Que fait cette requête ? Exécute-la pour vérifier.
SELECT ProductID, Designation
FROM product
WHERE Designation LIKE '%Décaféiné%'Voir la solution
Elle affiche l'identifiant et la désignation de tous les produits dont la désignation contient le mot « Décaféiné », où qu'il soit : le % avant et après autorise n'importe quel texte de chaque côté. Elle renvoie 31 produits.
Question 7.3
Affiche les colonnes CustomerID et CustomerName des clients dont le nom se termine par la lettre « E ».
Ta réponse
-- Question 7.3 : écris ta requête ici
SELECT Voir la solution
SELECT CustomerID, CustomerName
FROM customer
WHERE CustomerName LIKE '%E'Le % en premier accepte n'importe quel début ; le E en dernier impose la dernière lettre. Les noms sont en majuscules dans la table, donc '%e' ne renverrait rien.
Question 7.4
Cette requête renvoie une erreur. Corrige-la, puis explique en commentaire ce qu'elle fait.
Ta réponse
SELECT CustomerName
FROM customer
WHERE CustomerName LIKE "D%"Voir la solution
-- Affiche le nom des clients qui commencent par la lettre D
SELECT CustomerName
FROM customer
WHERE CustomerName LIKE 'D%'Le motif "D%" était entre guillemets doubles : le SGBD cherchait une colonne nommée D%. Une valeur s'écrit entre guillemets simples. Exécuter la requête et lire le message d'erreur est souvent le moyen le plus rapide de comprendre ce qui ne va pas.
BETWEEN … AND …
BETWEEN sélectionne les valeurs comprises entre deux bornes, bornes incluses. Il fonctionne avec des nombres et des dates ; les dates s'écrivent au format 'AAAA-MM-JJ'.
SELECT CustomerID, ProductID, "VolKilo (COPA)", "NOS (COPA)", Date
FROM perform21
WHERE Date BETWEEN '2021-09-01' AND '2021-12-01'Cette requête renvoie les ventes de septembre à décembre 2021 : les deux mois cités font partie du résultat.
Question 7.5
Dans perform25, affiche les colonnes CustomerID, ProductID, Date et "GP (COPA)" des ventes réalisées au premier trimestre 2025 (janvier, février et mars) dont la marge brute est comprise entre 50 000 et 100 000.
Ta réponse
-- Question 7.5 : écris ta requête ici
SELECT Voir la solution
SELECT CustomerID, ProductID, Date, "GP (COPA)"
FROM perform25
WHERE Date BETWEEN '2025-01-01' AND '2025-03-01'
AND "GP (COPA)" BETWEEN 50000 AND 100000On combine deux conditions avec AND (voir plus bas). Les mois étant datés du premier jour, '2025-03-01' inclut bien tout mars.
IN : une liste de valeurs
IN évite d'enchaîner les égalités. Ces deux filtres sont équivalents :
SELECT CustomerID, CustomerName, Channel
FROM customer
WHERE Channel IN ('E-commerce', 'Hors domicile')SELECT CustomerID, CustomerName, Channel
FROM customer
WHERE Channel = 'E-commerce' OR Channel = 'Hors domicile'Question 7.6
Affiche le nom (CustomerName) et le commercial (KeyAccount) des clients suivis par Paul, Ali ou Inès.
Ta réponse
-- Question 7.6 : écris ta requête ici
SELECT Voir la solution
SELECT CustomerName, KeyAccount
FROM customer
WHERE KeyAccount IN ('Paul', 'Ali', 'Inès')Remarque en passant : Paul a quitté l'entreprise fin 2025 (voir la table key_account), mais trois clients lui sont toujours rattachés. C'est typiquement le genre d'incohérence qu'un analyste doit signaler.
IS NULL : les valeurs manquantes
NULL signifie « valeur inconnue ». Ce n'est ni zéro ni un texte vide, et on ne le compare pas avec = : WHERE SubCategory = NULL ne renvoie jamais rien. On écrit IS NULL ou IS NOT NULL.
SELECT *
FROM customer
WHERE CustomerName IS NULLLes clients 17 et 18 n'ont aucune information : ce sont des lignes à faire corriger dans la source.
AND, OR et NOT
AND exige que toutes les conditions soient vraies. OR se contente d'une seule. NOT inverse une condition.
Question 7.7
Que font ces deux requêtes ? Pourquoi la seconde renvoie-t-elle plus de lignes ?
SELECT *
FROM customer
WHERE CustomerName LIKE 'D%' AND StrategicCustomer = 'Yes'SELECT *
FROM customer
WHERE CustomerName LIKE 'D%' OR StrategicCustomer = 'Yes'Voir la solution
La première affiche les clients stratégiques dont le nom commence par D : les deux conditions doivent être vraies, il n'en reste qu'un (DTC WEBSALES).
La seconde affiche les clients dont le nom commence par D ou qui sont stratégiques : une seule condition suffit, d'où 14 lignes. OR élargit le résultat, AND le restreint.
Question 7.8
Dans la table product, affiche toutes les colonnes des produits dont la sous-catégorie (SubCategory) est absente et dont la catégorie (Category) vaut 'Others'.
Ta réponse
-- Question 7.8 : écris ta requête ici
SELECT Voir la solution
SELECT *
FROM product
WHERE SubCategory IS NULL
AND Category = 'Others'On teste l'absence de valeur avec IS NULL, jamais avec = NULL. Trois produits répondent aux deux conditions ; leur marque vaut #N/A, signe d'une erreur de formule dans le fichier source.
Question 7.9
Affiche les colonnes ProductID, Category, SubCategory et Brand des produits dont la sous-catégorie est absente ou dont la catégorie vaut 'Others'. Le résultat est-il le même qu'à la question 7.8 ?
Ta réponse
-- Question 7.9 : écris ta requête ici
SELECT Voir la solution
SELECT ProductID, Category, SubCategory, Brand
FROM product
WHERE SubCategory IS NULL
OR Category = 'Others'Non : avec OR, il suffit qu'une des deux conditions soit vraie. On obtient 137 produits au lieu de 3 : tous ceux de la catégorie Others, plus les produits d'autres catégories sans sous-catégorie.
Les parenthèses et la priorité
Quand on mélange AND et OR, le SGBD évalue d'abord les AND, comme une multiplication avant une addition. Les parenthèses imposent un autre ordre, exactement comme en calcul.
-- Capsules intenses OU produits bio (de n'importe quelle catégorie) : 80 lignes
SELECT ProductID, Category, Intensity, IsOrganic
FROM product
WHERE Category = 'Capsules' AND Intensity >= 10 OR IsOrganic = 'Yes'-- Capsules qui sont intenses OU bio : 25 lignes
SELECT ProductID, Category, Intensity, IsOrganic
FROM product
WHERE Category = 'Capsules' AND (Intensity >= 10 OR IsOrganic = 'Yes')Question 7.10
Dans perform21, affiche toutes les ventes de septembre à décembre 2021 dont le taux de marge dépasse 30 %. Le taux de marge est la marge brute divisée par le chiffre d'affaires : "GP (COPA)" / "NOS (COPA)".
Ta réponse
-- Question 7.10 : écris ta requête ici
SELECT Voir la solution
SELECT *
FROM perform21
WHERE Date BETWEEN '2021-09-01' AND '2021-12-01'
AND "GP (COPA)" / "NOS (COPA)" > 0.3Une condition peut porter sur un calcul. 30 % s'écrit 0.3, avec un point décimal. perform21 ne contient aucune vente à 0 ; sur une autre année, il faudrait écarter ces lignes ("NOS (COPA)" > 0), car une division par zéro donne NaN dans DuckDB, une valeur que DuckDB considère comme plus grande que tous les nombres.
Question 7.11
Le service qualité veut la liste des capsules (Category = 'Capsules') encore commercialisées (Status = 'Active') dont l'intensité est d'au moins 10. Affiche leur ProductID, leur Designation et leur Intensity.
Ta réponse
-- Question 7.11 : écris ta requête ici
SELECT Voir la solution
SELECT ProductID, Designation, Intensity
FROM product
WHERE Category = 'Capsules'
AND Status = 'Active'
AND Intensity >= 10Trois conditions reliées par AND : un produit doit respecter les trois pour apparaître.
Ordre d'écriture et ordre d'exécution
On écrit les clauses dans cet ordre :
SELECT: les colonnes à afficher ;FROM: la table source ;WHERE: le filtre sur les lignes.
Mais le SGBD les exécute dans un autre ordre :
FROM: il identifie la table ;WHERE: il garde les lignes qui respectent la condition ;SELECT: il ne conserve que les colonnes demandées.
Cette différence explique une erreur classique : un alias créé dans le SELECT (avec AS) n'existe pas encore au moment où WHERE est évalué. Dans la plupart des SGBD, on ne peut donc pas filtrer sur un alias.
-- Dans PostgreSQL ou SQL Server, cette requête échoue : marge n'existe pas encore pendant le WHERE.
-- DuckDB l'accepte par commodité, mais mieux vaut ne pas en prendre l'habitude.
SELECT *, "GP (COPA)" / "NOS (COPA)" AS marge
FROM perform21
WHERE marge > 0.3Question 7.12
Affiche les ventes de Leclerc (CustomerID = 12) de l'année 2025 qui sont des retours (chiffre d'affaires négatif), avec les colonnes CustomerID, ProductID, Date, "VolKilo (COPA)" et "NOS (COPA)".
Ta réponse
-- Question 7.12 : écris ta requête ici
SELECT Voir la solution
SELECT CustomerID, ProductID, Date, "VolKilo (COPA)", "NOS (COPA)"
FROM perform25
WHERE CustomerID = 12
AND "NOS (COPA)" < 0La table perform25 ne contient que l'année 2025 : inutile de filtrer sur la date. Leclerc compte 24 lignes de retour cette année-là.