Leçon 3/7 8 min

Filtrer et trier

Le filtre WHERE en profondeur (AND, OR, NOT, LIKE, IN, BETWEEN, IS NULL) et le tri multi-colonnes avec ORDER BY.

FR EN

Le problème : « les clients actifs de l'Est qui n'ont pas d'email »

Le marketing débarque avec une demande tordue : « Je veux les clients de Besançon ou Dijon, inscrits entre janvier et mars, dont le nom commence par un M, et qui n'ont pas renseigné de téléphone. »

Une seule condition WHERE prix > 20 ne suffit plus. Il faut combiner plusieurs conditions avec précision. C'est tout l'art de la clause WHERE avancée. On travaille sur la table clients :

id | nom          | ville     | telephone   | inscrit_le
---+--------------+-----------+-------------+-----------
1  | Marie Dupont | Besançon  | 0601020304  | 2026-01-15
2  | Karim Benali | Dijon     | NULL        | 2026-02-03
3  | Léa Martin   | Lyon      | 0708091011  | 2026-03-21

Comparer et combiner : =, <, >, AND, OR, NOT

Les opérateurs de comparaison de base : = (égal), <> ou != (différent), <, >, <=, >=.

Pour combiner plusieurs conditions, on utilise AND (toutes vraies), OR (au moins une vraie) et NOT (l'inverse) :

SELECT nom, ville
FROM clients
WHERE ville = 'Besançon' AND telephone IS NOT NULL;

Attention aux parenthèses quand vous mélangez AND et OR. WHERE a = 1 OR a = 2 AND b = 3 ne fait pas ce que vous croyez : AND est prioritaire sur OR. Mettez des parenthèses explicites : WHERE (a = 1 OR a = 2) AND b = 3.

LIKE, IN, BETWEEN, IS NULL

LIKE cherche un motif dans du texte. Le caractère % remplace « n'importe quelle suite de caractères », _ remplace exactement un caractère :

SELECT nom
FROM clients
WHERE nom LIKE 'M%';   -- les noms commençant par M

IN teste l'appartenance à une liste, bien plus lisible qu'une cascade de OR :

SELECT nom, ville
FROM clients
WHERE ville IN ('Besançon', 'Dijon');

BETWEEN teste un intervalle (bornes incluses), idéal pour les dates et les nombres :

SELECT nom, inscrit_le
FROM clients
WHERE inscrit_le BETWEEN '2026-01-01' AND '2026-03-31';

NULL n'est pas une valeur ordinaire. telephone = NULL ne marche jamais, même si la valeur est vide. NULL veut dire « inconnu », et rien n'est égal à l'inconnu. Utilisez IS NULL ou IS NOT NULL :

SELECT nom FROM clients WHERE telephone IS NULL;

Trier sur plusieurs colonnes

ORDER BY accepte plusieurs colonnes, séparées par des virgules. Le tri se fait de gauche à droite : d'abord par la première colonne, puis la deuxième départage les égalités.

SELECT nom, ville, inscrit_le
FROM clients
ORDER BY ville ASC, inscrit_le DESC;

Ici, les clients sont d'abord groupés par ville (de A à Z), et à l'intérieur de chaque ville, du plus récemment inscrit au plus ancien.

La requête finale du marketing combine tout :

SELECT nom, ville
FROM clients
WHERE ville IN ('Besançon', 'Dijon')
  AND inscrit_le BETWEEN '2026-01-01' AND '2026-03-31'
  AND nom LIKE 'M%'
  AND telephone IS NULL
ORDER BY ville, nom;

The problem: "active eastern customers with no email"

Marketing shows up with a tricky request: "I want customers from Besancon or Dijon, registered between January and March, whose name starts with an M, and who have no phone number."

A single WHERE prix > 20 condition is no longer enough. You need to combine several conditions precisely. This is the whole art of the advanced WHERE clause. We work on the clients table:

id | nom          | ville     | telephone   | inscrit_le
---+--------------+-----------+-------------+-----------
1  | Marie Dupont | Besancon  | 0601020304  | 2026-01-15
2  | Karim Benali | Dijon     | NULL        | 2026-02-03
3  | Lea Martin   | Lyon      | 0708091011  | 2026-03-21

Compare and combine: =, <, >, AND, OR, NOT

The basic comparison operators: = (equal), <> or != (not equal), <, >, <=, >=.

To combine conditions, use AND (all true), OR (at least one true) and NOT (the opposite):

SELECT nom, ville
FROM clients
WHERE ville = 'Besancon' AND telephone IS NOT NULL;

Watch out for parentheses when mixing AND and OR. WHERE a = 1 OR a = 2 AND b = 3 does not do what you think: AND has priority over OR. Use explicit parentheses: WHERE (a = 1 OR a = 2) AND b = 3.

LIKE, IN, BETWEEN, IS NULL

LIKE searches for a pattern in text. The % character replaces "any sequence of characters", _ replaces exactly one character:

SELECT nom
FROM clients
WHERE nom LIKE 'M%';   -- names starting with M

IN tests membership in a list, far more readable than a cascade of OR:

SELECT nom, ville
FROM clients
WHERE ville IN ('Besancon', 'Dijon');

BETWEEN tests a range (bounds included), ideal for dates and numbers:

SELECT nom, inscrit_le
FROM clients
WHERE inscrit_le BETWEEN '2026-01-01' AND '2026-03-31';

NULL is not an ordinary value. telephone = NULL never works, even if the value is empty. NULL means "unknown", and nothing equals the unknown. Use IS NULL or IS NOT NULL:

SELECT nom FROM clients WHERE telephone IS NULL;

Sorting on several columns

ORDER BY accepts several columns, separated by commas. Sorting goes left to right: first by the first column, then the second breaks ties.

SELECT nom, ville, inscrit_le
FROM clients
ORDER BY ville ASC, inscrit_le DESC;

Here, customers are first grouped by city (A to Z), and within each city, from most recently registered to oldest.

The final marketing query combines everything:

SELECT nom, ville
FROM clients
WHERE ville IN ('Besancon', 'Dijon')
  AND inscrit_le BETWEEN '2026-01-01' AND '2026-03-31'
  AND nom LIKE 'M%'
  AND telephone IS NULL
ORDER BY ville, nom;

À vous d'essayer — la base est déjà remplie :

CREATE TABLE commandes (id INTEGER, client TEXT, ville TEXT, montant REAL);
INSERT INTO commandes VALUES (1, 'Alice Durand', 'Dijon', 120.50);
INSERT INTO commandes VALUES (2, 'Marc Petit', 'Lyon', 45.00);
INSERT INTO commandes VALUES (3, 'Léa Martin', 'Dijon', 230.90);
INSERT INTO commandes VALUES (4, 'Paul Roux', 'Lyon', 89.00);

SELECT client, montant
FROM commandes
WHERE ville = 'Dijon' AND montant > 100
ORDER BY montant DESC;
Avec l'IA

Faites traduire une demande métier en SQL par l'IA, puis vérifiez les pièges (NULL, parenthèses AND/OR) :

Table clients (id, nom, ville, telephone, inscrit_le). Écris une requête SQL pour les clients de Besançon ou Dijon, inscrits entre le 1er janvier et le 31 mars 2026, dont le nom commence par M et qui n'ont pas de téléphone. Trie par ville puis par nom. Attention : gère correctement le test du téléphone absent (NULL) et mets les parenthèses nécessaires entre les AND et OR. Explique pourquoi.
Ré-explique sans regarder

Sans relire la réponse de l'IA : pourquoi WHERE telephone = NULL ne renvoie-t-il jamais la moindre ligne, et qu'écris-tu à la place ?

Une bonne explication dit : NULL signifie « valeur inconnue », pas « vide ». En SQL, toute comparaison avec NULL via = ou <> renvoie UNKNOWN, jamais TRUE : la ligne est donc exclue. On teste l'absence de valeur avec IS NULL (et la présence avec IS NOT NULL), les seuls opérateurs conçus pour ça.
Exercice : Filtrez les clients

Écrivez une requête qui renvoie les clients de Dijon OU Lyon (utilisez IN) dont le téléphone est renseigné (utilisez IS NOT NULL), triés par nom. Pensez à WHERE, IN, IS NOT NULL et ORDER BY.

Accepter ou rejeter le code de l'IA

Tu as demandé « les clients de Dijon ou Lyon dont le montant dépasse 100 ». L'IA propose ce code. Ton rôle de relecteur : l'accepter tel quel ou le rejeter, et dire pourquoi.

SELECT client, ville, montant
FROM commandes
WHERE ville = 'Dijon' OR ville = 'Lyon' AND montant > 100;
À rejeter. AND est prioritaire sur OR, donc la base lit ceci comme ville = 'Dijon' OR (ville = 'Lyon' AND montant > 100) : tous les clients de Dijon ressortent, même ceux à 10 €, alors que le filtre montant ne s'applique qu'à Lyon. Le réflexe pro : parenthéser l'alternative de villes, WHERE (ville = 'Dijon' OR ville = 'Lyon') AND montant > 100 (ou mieux, ville IN ('Dijon','Lyon')).
Rappel libre

Sans remonter dans la leçon : que filtre WHERE nom LIKE 'M%', et dans ORDER BY ville ASC, inscrit_le DESC que fait la deuxième colonne ?

LIKE 'M%' garde les noms qui commencent par M : le % remplace n'importe quelle suite de caractères (alors que '%M' filtrerait ceux qui finissent par M). Dans ORDER BY ville ASC, inscrit_le DESC, le tri se fait d'abord par ville de A à Z ; la deuxième colonne, inscrit_le DESC, ne sert qu'à départager les lignes d'une même ville, du plus récent au plus ancien.
Comment tester qu'une colonne est vide (sans valeur) ?
Que renvoie LIKE 'M%' ?
Dans ORDER BY ville, nom, à quoi sert la deuxième colonne ?
Prochaine étape

Filtrer et trier, c'est répondre ligne par ligne. La prochaine étape change d'échelle : compter, totaliser et faire des moyennes par groupe avec COUNT, SUM, AVG, GROUP BY et HAVING.

Leçon 4 : Agréger et regrouper →
Besoin d'un développeur pour votre projet ?

Réponse sous 24h · Sans engagement