Vous avez une table pleine de données et une question précise : quels produits coûtent moins de cinquante unités ? Quels clients se sont inscrits ce mois-ci, du plus récent au plus ancien ? Répondre à ces questions, c est exactement ce que fait la commande SELECT, accompagnée de WHERE pour filtrer et de ORDER BY pour trier. C est la requête la plus utilisée de tout SQL, et la maîtriser rend immédiatement autonome sur la majorité des besoins quotidiens.
Dans ce tutoriel, nous interrogeons la base TechStock, la boutique de matériel informatique qui sert de fil conducteur. À la fin, vous saurez extraire précisément les lignes voulues, les filtrer selon n importe quel critère, gérer correctement les valeurs absentes, et présenter le résultat trié et paginé.
🎯 Ce que vous allez apprendre
- Sélectionner des colonnes précises et leur donner des alias lisibles.
- Filtrer les lignes avec WHERE et tous ses opérateurs (=, <>, >, BETWEEN, IN, LIKE).
- Gérer les valeurs NULL sans tomber dans le piège classique.
- Combiner plusieurs conditions avec AND, OR et des parenthèses.
- Trier le résultat avec ORDER BY, sur une ou plusieurs colonnes.
- Limiter et paginer les résultats avec LIMIT et OFFSET.
🛠️ Ce que vous allez construire
Vous allez écrire, une par une, les requêtes de consultation dont la boutique a besoin au quotidien : la liste du catalogue filtrée par prix, la recherche de clients par ville, le classement des produits par stock. À la fin, ces requêtes forment la base de tout futur écran de consultation de l application.
Prérequis
- Un moteur installé : PostgreSQL ou SQLite (les requêtes ci-dessous fonctionnent sur les deux).
- La base TechStock créée. Un test express : si vous savez ce qu est une table et une colonne, vous êtes prêt ; sinon, lisez d abord le guide d introduction lié plus haut.
- ⏱️ Temps estimé : environ 40 minutes.
Pour que les exemples renvoient des résultats, insérons quelques produits de démonstration :
INSERT INTO categories (nom) VALUES
('Claviers'), ('Souris'), ('Câbles'), ('Écrans');
INSERT INTO produits (nom, prix, stock, categorie_id) VALUES
('Clavier mécanique AZERTY', 45.00, 30, 1),
('Clavier sans fil', 25.50, 0, 1),
('Souris optique', 12.00, 120, 2),
('Souris gamer', 39.90, 8, 2),
('Câble USB-C 1m', 6.00, 500, 3),
('Écran 24 pouces', 110.00, 5, 4),
('Écran 27 pouces', 180.00, NULL, 4);
Étape 1 — Choisir les colonnes avec SELECT
Avant de filtrer ou de trier, il faut dire au moteur ce que l on veut voir. SELECT liste les colonnes à afficher, suivi de FROM qui indique la table source. La toute première requête possible est donc de tout afficher, en utilisant l étoile, qui signifie toutes les colonnes.
SELECT * FROM produits;
Cette requête renvoie l intégralité de la table : toutes les lignes, toutes les colonnes. C est pratique pour explorer, mais en pratique on évite l étoile dans une application : elle lit des colonnes inutiles et se casse si le schéma change. On préfère nommer explicitement ce dont on a besoin, et au passage renommer une colonne avec un alias grâce au mot-clé AS pour un affichage plus clair :
SELECT nom AS produit,
prix AS prix_unitaire
FROM produits;
Le résultat ne comporte plus que deux colonnes, et leurs en-têtes portent les noms choisis. L alias ne modifie pas la table : il n affecte que l affichage du résultat. Vous pouvez aussi calculer des colonnes à la volée, par exemple le prix augmenté d une taxe fictive de dix-huit pour cent :
SELECT nom,
prix,
prix * 1.18 AS prix_ttc
FROM produits;
SQL accepte les expressions arithmétiques directement dans le SELECT. La colonne prix_ttc n existe pas dans la table : elle est calculée pour chaque ligne au moment de l affichage.
✅ Point d étape — Vous savez afficher tout ou partie d une table et créer des colonnes calculées. Vérifiez qu une requête sur deux colonnes renvoie bien deux colonnes nommées comme vos alias.
Étape 2 — Filtrer les lignes avec WHERE
Afficher toute la table est rarement utile : on veut presque toujours un sous-ensemble. La clause WHERE pose une condition que chaque ligne doit satisfaire pour être conservée. Le moteur évalue la condition ligne par ligne et ne garde que celles pour lesquelles elle est vraie.
SELECT nom, prix
FROM produits
WHERE prix < 50;
Ici, seules les lignes dont le prix est inférieur à cinquante apparaissent. Les opérateurs de comparaison disponibles sont l égalité (=), la différence (<> ou !=), et les comparaisons d ordre (>, <, >=, <=). Ils fonctionnent sur les nombres, mais aussi sur les dates et, dans l ordre alphabétique, sur le texte.
Plusieurs opérateurs spécialisés rendent les filtres plus expressifs. BETWEEN teste un intervalle bornes incluses ; IN teste l appartenance à une liste ; LIKE recherche un motif de texte, où le caractère pourcentage remplace n importe quelle suite de caractères.
-- Produits entre 10 et 50 inclus
SELECT nom, prix FROM produits
WHERE prix BETWEEN 10 AND 50;
-- Produits de plusieurs catégories précises
SELECT nom FROM produits
WHERE categorie_id IN (1, 2);
-- Produits dont le nom commence par Clavier
SELECT nom FROM produits
WHERE nom LIKE 'Clavier%';
Le filtre LIKE est sensible à la casse sur certains moteurs ; PostgreSQL propose ILIKE pour ignorer la casse. Retenez que BETWEEN inclut ses deux bornes, ce qui surprend parfois.
✅ Point d étape — Lancez les trois requêtes ci-dessus. Vous devriez voir respectivement les produits de la tranche de prix, ceux des catégories 1 et 2, et les claviers. Si une requête renvoie zéro ligne, vérifiez vos données insérées.
Étape 3 — Gérer les valeurs NULL
Souvenez-vous : NULL signifie absence de valeur, et non zéro. Dans nos données, l écran 27 pouces a un stock NULL, parce qu il n a pas encore été inventorié. Tentons naïvement de le retrouver :
-- INCORRECT : ne renvoie jamais rien
SELECT nom FROM produits WHERE stock = NULL;
Cette requête ne renvoie aucune ligne, même si un stock est NULL. La raison est fondamentale : toute comparaison avec NULL donne le résultat inconnu, jamais vrai. Pour tester l absence de valeur, SQL impose un opérateur dédié :
SELECT nom FROM produits WHERE stock IS NULL;
SELECT nom FROM produits WHERE stock IS NOT NULL;
La première requête retrouve enfin l écran non inventorié, la seconde liste tous les autres. C est l un des pièges les plus fréquents chez les débutants : retenez que NULL se teste avec IS, jamais avec le signe égal.
✅ Point d étape — La requête IS NULL doit renvoyer exactement la ligne de l écran 27 pouces. Si elle renvoie tout ou rien, relisez la condition.
Étape 4 — Combiner plusieurs conditions
Les besoins réels combinent souvent plusieurs critères : les produits abordables ET en stock, ou bien d une catégorie OU d une autre. Les mots-clés AND et OR relient les conditions, et NOT en inverse une. Quand on mélange AND et OR, les parenthèses deviennent indispensables, car AND est prioritaire sur OR, comme la multiplication l est sur l addition.
-- Produits abordables ET réellement disponibles
SELECT nom, prix, stock FROM produits
WHERE prix < 50 AND stock > 0;
-- Claviers OU souris, mais seulement à moins de 40
SELECT nom, prix FROM produits
WHERE (categorie_id = 1 OR categorie_id = 2)
AND prix < 40;
Dans la seconde requête, les parenthèses garantissent que la condition de catégorie est évaluée comme un bloc avant d être combinée au prix. Sans elles, le moteur lirait « catégorie 1, ou bien (catégorie 2 et prix sous 40) », ce qui donnerait un résultat tout autre. En cas de doute, mettez toujours des parenthèses : elles ne coûtent rien et lèvent toute ambiguïté.
✅ Point d étape — La première requête exclut le clavier sans fil, dont le stock est à zéro. Vérifiez sa présence ou son absence pour confirmer que votre filtre combiné fonctionne.
Étape 5 — Trier avec ORDER BY
Un résultat non trié sort dans un ordre non garanti, qui dépend de la mécanique interne du moteur. Pour imposer un ordre, on ajoute ORDER BY suivi de la ou des colonnes de tri. Par défaut le tri est croissant (ASC) ; on précise DESC pour décroissant.
-- Du moins cher au plus cher
SELECT nom, prix FROM produits
ORDER BY prix ASC;
-- Les mieux approvisionnés d abord
SELECT nom, stock FROM produits
ORDER BY stock DESC;
On peut trier sur plusieurs colonnes : le moteur applique le second critère uniquement pour départager les ex aequo du premier. Trions par catégorie, puis par prix décroissant à l intérieur de chaque catégorie :
SELECT categorie_id, nom, prix FROM produits
ORDER BY categorie_id ASC, prix DESC;
Une question revient toujours : où vont les NULL dans un tri ? Le comportement varie selon le moteur. PostgreSQL place les NULL en dernier dans un tri croissant, et propose les clauses NULLS FIRST et NULLS LAST pour décider explicitement. Préciser ce point évite les mauvaises surprises sur les colonnes pouvant contenir des valeurs absentes.
✅ Point d étape — Le tri par prix croissant doit placer le câble USB-C en tête et l écran 27 pouces en queue. Cet ordre confirme que le tri s applique correctement.
Étape 6 — Limiter et paginer
Une table de production peut contenir des millions de lignes ; on en affiche rarement plus de quelques dizaines à la fois. La clause LIMIT borne le nombre de lignes renvoyées, et OFFSET indique combien en sauter, ce qui permet de paginer.
-- Les 3 produits les plus chers
SELECT nom, prix FROM produits
ORDER BY prix DESC
LIMIT 3;
-- La deuxième page de 3 produits
SELECT nom, prix FROM produits
ORDER BY prix DESC
LIMIT 3 OFFSET 3;
Un point crucial : LIMIT n a de sens qu accompagné d un ORDER BY. Sans tri, le moteur est libre de renvoyer trois lignes quelconques, et la pagination devient incohérente d un appel à l autre. La norme SQL définit aussi une syntaxe équivalente, FETCH FIRST n ROWS ONLY, mais LIMIT reste la forme la plus répandue.
✅ Point d étape — La requête des trois produits les plus chers doit renvoyer les deux écrans et le clavier mécanique. La page suivante montre les produits intermédiaires, sans recoupement.
Étape 7 — Éliminer les doublons avec DISTINCT
Quand on ne sélectionne qu une colonne, des valeurs identiques apparaissent souvent plusieurs fois. Pour ne garder que les valeurs distinctes, on ajoute DISTINCT juste après SELECT. C est utile pour répondre à une question comme « quelles catégories sont effectivement représentées dans le catalogue ? ».
SELECT DISTINCT categorie_id
FROM produits
ORDER BY categorie_id;
Le résultat liste chaque identifiant de catégorie une seule fois, même si plusieurs produits la partagent. DISTINCT porte sur l ensemble des colonnes sélectionnées : deux lignes ne sont éliminées que si elles sont identiques sur toutes les colonnes du SELECT.
Vérification finale
Réunissons tout dans une requête qui ressemble à un vrai besoin métier : « les produits disponibles de moins de cent unités, du plus cher au moins cher, limités aux cinq premiers ». Elle combine filtre, gestion de la disponibilité, tri et limite.
SELECT nom, prix, stock
FROM produits
WHERE prix < 100 AND stock > 0
ORDER BY prix DESC
LIMIT 5;
Si cette requête vous semble limpide et que vous pouvez prédire son résultat avant de l exécuter, vous avez acquis la brique fondamentale de SQL.
🐞 Pièges fréquents
| Symptôme | Cause probable | Correctif |
|---|---|---|
| WHERE stock = NULL ne renvoie rien | Comparaison directe avec NULL | Utiliser IS NULL |
| Résultat AND/OR inattendu | Priorité de AND sur OR | Encadrer les OR de parenthèses |
| Ordre des lignes variable | Pas de ORDER BY | Toujours trier avant LIMIT |
| LIKE ne trouve pas un texte | Sensibilité à la casse | Utiliser ILIKE sur PostgreSQL |
| BETWEEN exclut une borne | Croyance erronée | BETWEEN inclut les deux bornes |
🌍 Réalités du terrain
Pour vous exercer sans rien installer, un fichier SQLite suffit et se manipule depuis un téléphone ou un ordinateur modeste. Quand vous afficherez ces résultats dans une application réelle, prenez dès maintenant l habitude de paginer avec LIMIT : charger des milliers de lignes d un coup gaspille la bande passante et alourdit l affichage, ce qui pèse lourd sur une connexion mobile limitée. Une page de vingt à cinquante lignes, récupérée à la demande, offre une expérience fluide même sur un réseau lent. Enfin, nommez explicitement vos colonnes plutôt que d utiliser l étoile : vous transférez moins de données et votre code résiste mieux aux évolutions du schéma.
✅ Récapitulatif
Vous savez désormais construire une requête de consultation complète : choisir les colonnes avec SELECT et les alias, filtrer les lignes avec WHERE et ses opérateurs, gérer correctement les NULL avec IS NULL, combiner des conditions avec AND, OR et des parenthèses, trier avec ORDER BY sur plusieurs colonnes, et paginer avec LIMIT et OFFSET. Ces opérations couvrent l essentiel des besoins de lecture sur une seule table. L étape suivante consiste à relier plusieurs tables entre elles.
🧾 Aide-mémoire
| Élément | Rôle |
|---|---|
| SELECT col1, col2 | Choisir les colonnes à afficher |
| AS alias | Renommer une colonne dans le résultat |
| WHERE condition | Filtrer les lignes |
| BETWEEN a AND b | Intervalle bornes incluses |
| IN (…) | Appartenance à une liste |
| LIKE ‘motif%’ | Recherche par motif de texte |
| IS NULL / IS NOT NULL | Tester l absence de valeur |
| ORDER BY col DESC | Trier le résultat |
| LIMIT n OFFSET m | Limiter et paginer |
| DISTINCT | Éliminer les doublons |
💪 À vous de jouer
1. Affichez les noms et prix des produits coûtant entre 20 et 120 unités, triés du moins cher au plus cher.
2. Trouvez tous les produits dont le stock est inconnu.
3. Affichez les deux produits les moins chers de la catégorie 2.
Voir une solution
-- 1
SELECT nom, prix FROM produits
WHERE prix BETWEEN 20 AND 120
ORDER BY prix ASC;
-- 2
SELECT nom FROM produits WHERE stock IS NULL;
-- 3
SELECT nom, prix FROM produits
WHERE categorie_id = 2
ORDER BY prix ASC
LIMIT 2;
Tutoriels associés
- Combiner des tables avec les jointures INNER, LEFT et auto-jointure
- Agréger et résumer avec GROUP BY et HAVING
Pour aller plus loin
- 🔝 Retour au guide : Apprendre le SQL
- Documentation SELECT PostgreSQL : postgresql.org
- Opérateurs de motif : LIKE et expressions
FAQ
Quelle différence entre WHERE et HAVING ? WHERE filtre les lignes individuelles avant tout regroupement ; HAVING filtre les groupes après un GROUP BY. Tant qu il n y a pas d agrégation, on utilise WHERE.
Pourquoi éviter SELECT * ? Parce qu il lit des colonnes inutiles, transfère plus de données et casse silencieusement si l ordre ou le nombre de colonnes change. Nommer les colonnes rend le code explicite et robuste.
LIKE ou égalité pour chercher un texte ? L égalité exige une correspondance exacte ; LIKE permet les correspondances partielles avec des motifs. Pour une recherche utilisateur, LIKE (ou ILIKE) est généralement plus adapté.
Le tri ralentit-il la requête ? Trier a un coût, surtout sur de gros volumes. Un index sur la colonne de tri peut l accélérer considérablement, sujet traité dans le tutoriel sur les index.
Mots-clés : requête SELECT, clause WHERE, ORDER BY, filtrer SQL, opérateurs SQL, valeurs NULL, LIMIT OFFSET.