Comprendre la clause MySQL ORDER BY en PHP
La clause ORDER BY trie les résultats d'une requête MySQL. Apprenez la syntaxe, l'ordre ascendant/descendant, les valeurs NULL et la sécurité en PHP.
Une requête SELECT sans ORDER BY retourne les lignes dans un ordre que MySQL ne garantit pas — il peut changer entre deux exécutions, selon la version du serveur ou après une maintenance de la table. La clause ORDER BY rend cet ordre explicite en triant le jeu de résultats selon une ou plusieurs colonnes. Cette page montre comment l'utiliser depuis PHP : la syntaxe, l'ordre ascendant ou descendant, le tri par plusieurs colonnes, l'emplacement des valeurs NULL, et comment trier par une colonne fournie par l'utilisateur en toute sécurité pour éviter une faille d'injection SQL.
Si vous débutez avec l'exécution de requêtes depuis PHP, commencez par la connexion à MySQL et la sélection de données.
Syntaxe
SELECT column1, column2, ...
FROM table_name
ORDER BY column1 [ASC | DESC], column2 [ASC | DESC], ...;ASCtrie par ordre croissant (A→Z, 0→9, du plus ancien au plus récent) et est la valeur par défaut —ORDER BY ageetORDER BY age ASCsont identiques.DESCtrie par ordre décroissant (Z→A, 9→0, du plus récent au plus ancien).- La direction s'applique par colonne, vous pouvez donc les mélanger :
ORDER BY country ASC, age DESC.
ORDER BY s'exécute après le filtrage WHERE et le GROUP BY, il ne trie donc que les lignes qui ont survécu à ces étapes. C'est la dernière clause avant LIMIT.
Un exemple de base
Ceci sélectionne les noms et les âges et trie les clients les plus âgés en premier :
<?php
$conn = new mysqli("localhost", "username", "password", "database");
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "SELECT name, age FROM customers ORDER BY age DESC";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
echo "Name: " . $row["name"] . " - Age: " . $row["age"] . "<br>";
}
} else {
echo "0 results";
}
$conn->close();
?>On se connecte avec la classe mysqli, on sélectionne name et age dans customers, et on utilise ORDER BY age DESC pour que l'âge le plus élevé apparaisse en premier. Remplacez DESC par ASC (ou supprimez-le) pour afficher les plus jeunes en premier.
Tri par plusieurs colonnes
Lorsque plusieurs lignes partagent la même valeur dans la première colonne de tri, la colonne suivante départage les égalités. L'ordre des colonnes dans la clause est l'ordre de priorité :
SELECT name, country, age
FROM customers
ORDER BY country ASC, age DESC;Ceci regroupe les clients par country par ordre alphabétique, et au sein de chaque pays liste les plus âgés en premier. Avec les données ci-dessous :
| name | country | age |
|---|---|---|
| Anna | Canada | 41 |
| Ben | Canada | 29 |
| Carla | Mexico | 50 |
ORDER BY country ASC, age DESC retourne Anna, Ben, Carla — Canada avant Mexico, et Anna avant Ben car 41 > 29.
Comment les valeurs NULL sont triées
Dans MySQL, NULL est traité comme inférieur à toute valeur non NULL :
- Avec
ASC, les lignes où la colonne de tri estNULLapparaissent en premier. - Avec
DESC, elles apparaissent en dernier.
Pour forcer les NULL à la fin quelle que soit la direction, triez d'abord sur le fait que la colonne est nulle :
SELECT name, last_login
FROM users
ORDER BY last_login IS NULL, last_login DESC;last_login IS NULL vaut 0 pour les vraies dates et 1 pour les nulls, donc les lignes non nulles (0) apparaissent avant les nulles (1).
Tri par une colonne choisie à l'exécution (en toute sécurité)
Un besoin courant est de laisser l'utilisateur choisir la colonne de tri — par exemple ?sort=name. Vous ne pouvez pas lier un nom de colonne ou le mot-clé ASC/DESC avec un paramètre de requête préparée ; les paramètres ne fonctionnent que pour les valeurs. Concaténer la requête brute dans le SQL serait une vulnérabilité d'injection SQL. Validez plutôt l'entrée contre une liste blanche :
<?php
// Map user input to known-good column names.
$allowedColumns = [
"name" => "name",
"age" => "age",
"date" => "created_at",
];
$sortKey = $_GET["sort"] ?? "name";
$column = $allowedColumns[$sortKey] ?? "name"; // fallback if unknown
$direction = (($_GET["dir"] ?? "asc") === "desc") ? "DESC" : "ASC";
// $column and $direction can now only be values we put in the code.
$sql = "SELECT name, age FROM customers ORDER BY $column $direction";
$result = $conn->query($sql);
?>L'utilisateur ne fournit qu'une clé de tableau ; le nom de colonne réel et la direction proviennent de constantes dans votre code, de sorte que les données non fiables n'atteignent jamais la chaîne de requête. C'est le seul endroit où construire du SQL par concaténation est acceptable — parce que chaque valeur possible est une valeur que vous avez écrite.
Remarque :
ORDER BYlui-même ne prend jamais de valeurs utilisateur, donc il n'utilise pas de paramètres liés. Toutes les valeursWHEREdans la même requête doivent toujours être liées avec une requête préparée.
Pièges courants
- Tri par une colonne de type string contenant des nombres (par exemple un
agestocké enVARCHAR) trie de manière lexicale :"10"vient avant"9". Stockez les nombres dans une colonne numérique, ou convertissez avecORDER BY CAST(age AS UNSIGNED). ORDER BYavecLIMITest la façon d'obtenir les "N meilleurs" résultats :ORDER BY age DESC LIMIT 5retourne les cinq plus âgés. SansORDER BY, les lignes queLIMITconserve sont imprévisibles. Voir limiter les données.- Trier un grand jeu de résultats peut être lent si aucun index ne couvre la colonne de tri ; un index sur la colonne
ORDER BYpermet à MySQL de sauter l'étape de tri.
Conclusion
ORDER BY transforme un ordre de lignes indéfini en un ordre défini. Retenez l'essentiel : ASC est la valeur par défaut, les colonnes sont appliquées de gauche à droite pour les départages, NULL trie bas, et une colonne de tri choisie par l'utilisateur doit être validée contre une liste blanche plutôt que concaténée aveuglément. Combiné avec WHERE pour le filtrage et LIMIT pour la pagination, cela vous donne un contrôle total sur les lignes retournées et leur ordre.