La commande SQL ORDER BY trie les lignes retournées par une requête selon une ou plusieurs colonnes, dans l’ordre croissant ou décroissant.
Table des matières
Syntaxe de base
La clause ORDER BY se place toujours en dernière position dans une requête, après FROM, WHERE, GROUP BY et HAVING. Elle utilise le mot-clé ASC pour un tri croissant et DESC pour un tri décroissant. ASC est appliqué par défaut lorsque aucun mot-clé n’est précisé après le nom de la colonne.
SELECT nom, prix FROM produits ORDER BY prix ASC;
Le moteur SQL exécute ORDER BY en dernier, après tous les filtres et regroupements, ce qui garantit que le tri porte sur le résultat final. Cette position en fin d’exécution permet également d’utiliser les alias définis dans SELECT directement dans ORDER BY.
Trier par ordre croissant avec ASC
ASC classe les valeurs numériques du plus petit au plus grand et les chaînes de caractères de A à Z. Cette option convient aux listes chronologiques, aux classements hiérarchiques et aux rapports de salaires. Le comportement des valeurs NULL dépend du SGBD : MySQL les place en début de liste, PostgreSQL en fin avec ASC.
La requête suivante classe les employés du salaire le plus faible au plus élevé.
SELECT nom, salaire
FROM employes
ORDER BY salaire ASC;
Les employés avec le salaire le plus bas apparaissent en premier dans le résultat. Vérifiez le comportement des valeurs NULL sur votre SGBD si la colonne triée peut contenir des valeurs manquantes.
Trier par ordre décroissant avec DESC
Voici les sections DESC et GROUP BY réécrites et étoffées, en respectant le prompt PHP officiel adapté au SQL :
Tri décroissant avec DESC
Le mot-clé DESC indique au moteur SQL de retourner les lignes dans l’ordre décroissant de la colonne spécifiée. Sans précision, SQL applique ASC par défaut : les résultats vont du plus petit au plus grand, du plus ancien au plus récent. Utiliser DESC est donc indispensable pour afficher les données les plus récentes ou les valeurs les plus élevées en premier. Ce besoin est particulièrement fréquent dans les tableaux de bord, les historiques de commandes ou les classements de scores.
-- Afficher les produits du plus cher au moins cher
SELECT nom, prix
FROM produits
ORDER BY prix DESC;
La colonne prix est triée du montant le plus élevé vers le plus bas. Si deux produits partagent le même prix, leur ordre relatif n’est pas garanti sans second critère de tri. Pour stabiliser ce cas, il suffit d’ajouter une seconde colonne après DESC, comme ORDER BY prix DESC, nom ASC.
DESC peut s’appliquer indépendamment sur chaque colonne dans un tri multi-colonnes. Chaque colonne porte son propre modificateur de direction, séparé par une virgule. Ce comportement permet des tris asymétriques comme un classement décroissant par score mais croissant par nom d’équipe.
-- Tri décroissant par note, puis croissant par nom d'élève
SELECT nom, note
FROM eleves
ORDER BY note DESC, nom ASC;
Les élèves ayant la note la plus haute apparaissent en premier, et ceux ayant la même note sont triés alphabétiquement. Ce pattern est un standard dans les tableaux de classement où deux critères de départage s’appliquent successivement. L’absence de DESC ou ASC sur une colonne applique silencieusement le tri croissant par défaut.
Trier sur plusieurs colonnes
Un tri multi-colonnes classe d’abord les lignes selon la première colonne, puis selon la seconde en cas d’égalité sur la première. Chaque colonne supplémentaire affine le classement pour les lignes qui partagent la même valeur précédente. Les mots-clés ASC et DESC s’appliquent indépendamment à chaque colonne.
La requête suivante trie les clients par ville par ordre alphabétique, puis par chiffre d’affaires décroissant au sein de chaque ville.
SELECT ville, nom, chiffre_affaires
FROM clients
ORDER BY ville ASC, chiffre_affaires DESC;
Les clients d’une même ville sont classés du chiffre d’affaires le plus élevé au plus faible. Un client de Bordeaux apparaît toujours après tous les clients d’Amiens, quelle que soit son chiffre d’affaires.
Trier sur une expression calculée
ORDER BY accepte une expression calculée ou un alias défini dans la requête de sélection pour trier sur une valeur qui n’existe pas directement dans la table. Le moteur calcule d’abord l’expression pour chaque ligne, puis trie les résultats selon cette valeur calculée. Cette forme évite de répéter l’expression dans la clause de tri.
La requête suivante classe les ventes par montant total calculé à partir du prix et de la quantité.
SELECT nom, prix * quantite AS total
FROM ventes
ORDER BY total DESC;
L’alias total est utilisable directement dans ORDER BY car cette clause s’exécute après SELECT. Vérifiez que l’expression ne contient pas de valeurs NULL qui fausseraient l’ordre du résultat.
Combiner ORDER BY et GROUP BY
ORDER BY s’utilise fréquemment après GROUP BY pour trier les groupes agrégés selon une valeur calculée. Dans l’ordre d’exécution SQL, GROUP BY s’exécute avant ORDER BY : les groupes sont d’abord constitués, puis triés. Il est donc possible de trier sur une fonction d’agrégation comme COUNT(), SUM() ou AVG(), car ces valeurs sont disponibles au moment où ORDER BY s’exécute. Sans ORDER BY, l’ordre d’affichage des groupes est indéterminé et peut varier d’une exécution à l’autre.
-- Nombre de commandes par client, du plus actif au moins actif
SELECT client_id, COUNT(*) AS nb_commandes
FROM commandes
GROUP BY client_id
ORDER BY nb_commandes DESC;
Les groupes sont triés par le résultat de COUNT(*), ce qui affiche les clients les plus actifs en tête de liste. L’alias nb_commandes est directement utilisable dans ORDER BY car il est défini dans le SELECT, exécuté avant le tri. Certains SGBDR comme MySQL autorisent cet alias ; d’autres comme des versions strictes de PostgreSQL exigent de répéter l’expression COUNT(*) dans ORDER BY.
-- Chiffre d'affaires total par catégorie, du plus rentable au moins rentable
SELECT categorie, SUM(prix * quantite) AS chiffre_affaires
FROM ventes
GROUP BY categorie
ORDER BY chiffre_affaires DESC;
Cette requête regroupe les ventes par catégorie, calcule le chiffre d’affaires total de chacune, puis les classe du plus rentable au moins rentable. Le filtre sur les groupes agrégés doit être placé dans HAVING et non dans WHERE, qui s’exécute avant la constitution des groupes. ORDER BY reste toujours la dernière clause exécutée dans la chaîne de traitement SQL.
Paginer les résultats avec LIMIT et OFFSET
ORDER BY garantit un ordre stable des résultats entre les pages d’une pagination avec LIMIT et OFFSET. Sans ORDER BY, la page 2 peut retourner des lignes déjà présentes en page 1 si le moteur change son plan d’exécution. Le même critère de tri doit être conservé sur toutes les pages d’une même pagination.
Les deux requêtes suivantes retournent respectivement la première et la deuxième page de dix clients triés par nom.
-- Page 1 : lignes 1 à 10
SELECT nom, email
FROM clients
ORDER BY nom ASC
LIMIT 10 OFFSET 0;
-- Page 2 : lignes 11 à 20
SELECT nom, email
FROM clients
ORDER BY nom ASC
LIMIT 10 OFFSET 10;
OFFSET 10 saute les dix premières lignes pour retourner les suivantes dans le même ordre. Vérifiez que la colonne utilisée dans ORDER BY est indexée pour éviter un tri complet de la table à chaque page.
Trier après une jointure
ORDER BY s’applique sur l’ensemble du résultat joint après que toutes les jointures ont été résolues. Les colonnes de tri doivent être préfixées par leur alias de table en cas d’ambiguïté entre plusieurs tables. Cette forme permet de trier simultanément sur des colonnes issues de tables différentes.
La requête suivante affiche les commandes triées par date décroissante puis par prix croissant, en associant clients, commandes et produits.
SELECT c.nom, p.prix, com.date_commande
FROM clients c
JOIN commandes com ON c.id = com.client_id
JOIN produits p ON com.produit_id = p.id
ORDER BY com.date_commande DESC, p.prix ASC;
Les commandes les plus récentes apparaissent en premier, et pour une même date, les produits les moins chers sont affichés en tête. Préfixez chaque colonne avec son alias de table pour éviter une erreur d’ambiguïté sur les colonnes portant le même nom dans plusieurs tables.
Bonnes pratiques
Règle 1 — Indexer les colonnes utilisées dans ORDER BYCREATE INDEX idx_nom ON clients(nom) évite un tri complet de la table et réduit le temps d’exécution sur les grandes tables.
Règle 2 — Préciser ASC ou DESC explicitementORDER BY prix DESC est plus lisible que ORDER BY prix seul, même si ASC est la valeur par défaut appliquée automatiquement.
Règle 3 — Conserver le même ORDER BY sur toute une pagination
Changer le critère de tri entre deux pages d’une pagination avec OFFSET produit des doublons ou des lignes manquantes dans les résultats.
Règle 4 — Préférer le nom de colonne au numéro de positionORDER BY prix DESC est plus maintenable que ORDER BY 3 DESC, car l’ajout d’une colonne dans SELECT décale les numéros et fausse le tri.
Règle 5 — Utiliser EXPLAIN pour vérifier l’utilisation des indexEXPLAIN SELECT * FROM clients ORDER BY nom révèle si le moteur effectue un tri en mémoire ou utilise un index existant.
Cas pratique métier
Un service commercial génère un rapport des dix meilleurs clients parisiens classés par chiffre d’affaires décroissant pour le trimestre en cours.
SELECT c.nom, c.ville, SUM(com.montant) AS chiffre_affaires
FROM clients c
JOIN commandes com ON c.id = com.client_id
WHERE c.ville = 'Paris'
AND com.date_commande >= '2026-01-01'
GROUP BY c.id, c.nom, c.ville
ORDER BY chiffre_affaires DESC
LIMIT 10;
Erreurs courantes
❌ Erreur : ORDER BY placé avant WHERE
SELECT nom FROM clients ORDER BY nom WHERE ville = 'Paris';
-- Le moteur rejette la requête car ORDER BY doit se placer en dernière position.
✅ Correct :
SELECT nom FROM clients WHERE ville = 'Paris' ORDER BY nom;
❌ Erreur : alias utilisé dans WHERE au lieu de ORDER BY
SELECT prix * quantite AS total FROM ventes WHERE total > 100;
-- WHERE s'exécute avant SELECT : l'alias total n'existe pas encore.
✅ Correct :
SELECT prix * quantite AS total FROM ventes WHERE prix * quantite > 100 ORDER BY total DESC;
❌ Erreur : tri instable sur une pagination sans colonne unique
SELECT nom FROM clients ORDER BY ville LIMIT 10 OFFSET 10;
-- Deux clients dans la même ville peuvent apparaître en double entre deux pages.
✅ Correct :
SELECT nom FROM clients ORDER BY ville ASC, id ASC LIMIT 10 OFFSET 10;
Sources : MySql , Postgresql