Comment écrire une requête SQL pour la pagination ?

Par :

,le

Le mot-clé SQL LIMIT restreint le nombre de lignes retournées par une requête, tandis qu’OFFSET définit la position de départ à partir de laquelle les lignes sont sélectionnées.

Syntaxe de base

La clause LIMIT se place toujours en dernière position dans une requête, après FROMWHERE et ORDER BY. Elle accepte un entier positif qui représente le nombre maximum de lignes à retourner. Sans ORDER BY, les lignes retournées par LIMIT suivent l’ordre physique arbitraire du stockage, ce qui produit des résultats imprévisibles.

SELECT nom, prix
FROM produits
ORDER BY prix ASC
LIMIT 5;

La requête retourne les cinq produits les moins chers, triés par prix croissant. Vérifiez que ORDER BY est toujours présent avant LIMIT pour garantir un résultat stable et reproductible.

Paginer les résultats avec OFFSET

OFFSET indique au moteur combien de lignes sauter avant de commencer à retourner les résultats. Il s’utilise toujours conjointement avec LIMIT pour diviser un résultat en pages successives. La formule de calcul de l’offset est (numéro_page - 1) × taille_page.

Les trois requêtes suivantes retournent respectivement les pages 1, 2 et 3 d’une liste de clients triés par nom.

-- Page 1 : lignes 1 à 10
SELECT nom FROM clients ORDER BY nom LIMIT 10 OFFSET 0;

-- Page 2 : lignes 11 à 20
SELECT nom FROM clients ORDER BY nom LIMIT 10 OFFSET 10;

-- Page 3 : lignes 21 à 30
SELECT nom FROM clients ORDER BY nom LIMIT 10 OFFSET 20;

Chaque page retourne exactement dix lignes en commençant à la position définie par OFFSET. Conservez le même critère ORDER BY sur toutes les pages pour éviter les doublons ou les lignes manquantes entre deux pages.

Compatibilité SGBD

La syntaxe LIMIT / OFFSET est standard sur MySQL, PostgreSQL, MariaDB et SQLite. SQL Server et Oracle utilisent des syntaxes propriétaires différentes pour obtenir le même résultat.

-- MySQL, PostgreSQL, SQLite : syntaxe standard
SELECT * FROM produits ORDER BY prix LIMIT 10 OFFSET 20;

-- SQL Server : TOP pour les limites simples
SELECT TOP 10 nom FROM clients ORDER BY nom;

-- SQL Server : OFFSET/FETCH pour la pagination
SELECT nom FROM clients
ORDER BY nom
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY;

-- Oracle 12c+ : FETCH FIRST recommandé
SELECT nom FROM clients
ORDER BY nom
FETCH FIRST 10 ROWS ONLY;
FonctionnalitéMySQLPostgreSQLSQL ServerOracle
LIMIT
OFFSET✅ OFFSET ROWS
TOP
FETCH FIRST✅ 8.0+✅ 12c+

Extraire les premières lignes d’un classement

LIMIT combiné à ORDER BY DESC retourne les lignes les mieux classées selon un critère numérique ou chronologique. Cette forme convient aux tops 10, aux dernières commandes ou aux produits les plus vendus. Le tri doit porter sur la colonne qui définit le classement souhaité.

La requête suivante retourne les cinq produits les plus vendus en janvier 2026.

SELECT produit, SUM(quantite) AS total_vendu
FROM ventes
WHERE MONTH(date_vente) = 1 AND YEAR(date_vente) = 2026
GROUP BY produit
ORDER BY total_vendu DESC
LIMIT 5;

GROUP BY calcule d’abord le total vendu par produit, ORDER BY trie par total décroissant, et LIMIT conserve uniquement les cinq premiers. Vérifiez que l’index sur date_vente est actif pour éviter un parcours complet de la table.

Paginer avec une jointure

LIMIT et OFFSET s’appliquent après que les jointures ont assemblé toutes les tables et que WHERE a filtré les lignes. Cette position garantit que la pagination porte sur le résultat final et non sur une table intermédiaire. Le tri doit être défini sur une colonne stable pour que les pages soient cohérentes.

La requête suivante retourne la troisième page de vingt produits électroniques dont le prix est compris entre 50 et 200 €.

SELECT p.nom, p.prix, c.nom AS categorie
FROM produits p
JOIN categories c ON p.categorie_id = c.id
WHERE p.prix BETWEEN 50 AND 200
  AND c.nom = 'Electronique'
ORDER BY p.nom ASC
LIMIT 20 OFFSET 40;

OFFSET 40 correspond à la troisième page de vingt éléments, soit les lignes 41 à 60. Vérifiez que WHERE est suffisamment sélectif pour réduire le volume avant que OFFSET ne compte les lignes à sauter.

Utiliser la pagination par curseur

La pagination par OFFSET devient lente sur les grandes tables car le moteur compte toutes les lignes sautées à chaque requête. La pagination par curseur utilise l’identifiant de la dernière ligne affichée comme point de départ. Cette technique maintient des performances constantes quelle que soit la profondeur de pagination.

La requête suivante retourne les vingt produits dont l’identifiant est supérieur au dernier identifiant affiché sur la page précédente.

-- Pagination par curseur après le produit id = 1500
SELECT id, nom, prix
FROM produits
WHERE id > 1500
ORDER BY id ASC
LIMIT 20;

Le moteur accède directement aux lignes après l’identifiant 1500 grâce à l’index sur id. Cette approche est jusqu’à cent fois plus rapide qu’un OFFSET 1500 sur une table de plusieurs millions de lignes.

Bonnes pratiques

Règle 1 — Toujours associer LIMIT à ORDER BY
SELECT nom FROM clients LIMIT 10 retourne des lignes dans un ordre arbitraire. ORDER BY nom garantit un résultat stable et reproductible entre deux exécutions.

Règle 2 — Ajouter l’identifiant en dernier critère de tri
ORDER BY nom ASC, id ASC évite les doublons entre pages quand plusieurs lignes partagent la même valeur de nom.

Règle 3 — Préférer la pagination par curseur au-delà de 10 000 lignes
WHERE id > dernier_id ORDER BY id LIMIT 20 maintient des performances constantes, contrairement à OFFSET qui ralentit proportionnellement à la profondeur de la page.

Règle 4 — Indexer les colonnes utilisées dans ORDER BY avec LIMIT
CREATE INDEX idx_nom ON clients(nom, id) permet au moteur d’utiliser l’index pour le tri et évite un parcours complet de la table.

Règle 5 — Tester les performances sur des volumes réels
Une requête avec OFFSET 990000 peut passer de 0,1 seconde à 30 secondes sur une table d’un million de lignes sans index adapté.

Cas pratique métier

Un site e-commerce affiche les dix commandes les plus récentes sur la page d’accueil du tableau de bord, avec le nom du client et le montant associé.

SELECT c.nom, com.date_commande, com.montant
FROM clients c
JOIN commandes com ON c.id = com.client_id
ORDER BY com.date_commande DESC
LIMIT 10;

Erreurs courantes

❌ Erreur : LIMIT sans ORDER BY
SELECT nom FROM clients LIMIT 10;
-- Les lignes retournées suivent l'ordre physique du disque, qui est imprévisible.

✅ Correct :
SELECT nom FROM clients ORDER BY nom ASC LIMIT 10;
❌ Erreur : LIMIT utilisé sur SQL Server
SELECT * FROM clients LIMIT 10;
-- LIMIT n'existe pas dans Transact-SQL et génère une erreur de syntaxe.

✅ Correct (SQL Server) :
SELECT TOP 10 * FROM clients ORDER BY nom;
❌ Erreur : OFFSET élevé sur grande table
SELECT * FROM clients ORDER BY id LIMIT 10 OFFSET 990000;
-- Le moteur compte 990 000 lignes avant de retourner les 10 suivantes.

✅ Correct (pagination par curseur) :
SELECT * FROM clients WHERE id > 990000 ORDER BY id LIMIT 10;

Sources: MySql ,Postgres , Sqlite , SQL Server