Dans le chapitre précédent, on a vu Pourquoi SQL ? Les bases de données expliquées. Tu sais maintenant interroger des données avec
SELECTetWHERE. On passe au niveau suivant.
🎯 Objectif : Maîtriser le tri avec ORDER BY, la pagination avec LIMIT, les fonctions d’agrégation (COUNT, SUM, AVG) et le regroupement avec GROUP BY / HAVING.
ORDER BY et LIMIT : trier et paginer
Sans ORDER BY, SQL ne garantit aucun ordre de résultat. Deux exécutions de la même requête peuvent donner des ordres différents. Si tu veux un résultat prévisible, trie explicitement.
-- Tri alphabétique (ASC par défaut)
SELECT * FROM servers ORDER BY hostname;
-- Tri décroissant par RAM
SELECT * FROM servers ORDER BY ram_gb DESC;
-- Tri multi-colonnes : d'abord par env, puis par CPU décroissant
SELECT * FROM servers
ORDER BY environment ASC, cpu_cores DESC;
-- Les 3 serveurs avec le plus de RAM
SELECT hostname, ram_gb FROM servers
ORDER BY ram_gb DESC
LIMIT 3;
-- Pagination : résultats 21 à 30
SELECT * FROM servers
ORDER BY server_id
LIMIT 10 OFFSET 20;
💡 LIMIT sans ORDER BY est un piège classique. Tu obtiens des résultats “aléatoires” — pas vraiment utile. Combine toujours les deux.
⚠️ En SQL Server, la syntaxe est SELECT TOP 5 * FROM servers au lieu de LIMIT. Le concept reste identique.
Fonctions d’agrégation
Les fonctions d’agrégation transforment un ensemble de lignes en une seule valeur. Ce sont les outils d’analyse de SQL.
Les 5 fonctions essentielles
-- Combien de serveurs au total ?
SELECT COUNT(*) AS total_servers FROM servers;
-- Compter les valeurs non-NULL uniquement
SELECT COUNT(ip_address) AS servers_with_ip FROM servers;
-- Somme des CPUs de tout le parc
SELECT SUM(cpu_cores) AS total_cpus FROM servers;
-- RAM moyenne (arrondie)
SELECT ROUND(AVG(ram_gb), 1) AS avg_ram FROM servers;
-- Min et Max en une requête
SELECT MIN(cpu_cores) AS min_cpus,
MAX(cpu_cores) AS max_cpus
FROM servers;
-- Combiner agrégation et WHERE
SELECT SUM(ram_gb) AS total_prod_ram
FROM servers
WHERE environment = 'production';
🔥 COUNT(*) compte toutes les lignes, COUNT(colonne) ignore les NULL. C’est une nuance importante quand tu as des données incomplètes.
GROUP BY : regrouper les données
GROUP BY est la clause qui rend SQL vraiment puissant pour l’analyse. Elle regroupe les lignes partageant une même valeur, puis applique une agrégation sur chaque groupe.
-- Nombre de serveurs par environnement
SELECT environment,
COUNT(*) AS server_count
FROM servers
GROUP BY environment;
| environment | server_count |
|---|---|
| production | 3 |
| development | 1 |
| staging | 1 |
Regroupement avec plusieurs agrégations
-- Stats complètes par environnement
SELECT environment,
COUNT(*) AS nb_servers,
SUM(ram_gb) AS total_ram,
ROUND(AVG(cpu_cores), 1) AS avg_cpus
FROM servers
GROUP BY environment
ORDER BY total_ram DESC;
Regroupement multi-colonnes
-- Serveurs par environnement ET par statut
SELECT environment, status,
COUNT(*) AS server_count
FROM servers
GROUP BY environment, status
ORDER BY environment, status;
💡 Règle d’or : toute colonne dans le SELECT qui n’est pas dans une fonction d’agrégation doit apparaître dans le GROUP BY. Sinon, PostgreSQL te renvoie une erreur.
HAVING : filtrer les groupes
WHERE filtre les lignes avant le regroupement. HAVING filtre les groupes après l’agrégation. C’est la distinction la plus importante de ce chapitre.
-- Environnements avec plus de 2 serveurs
SELECT environment, COUNT(*) AS server_count
FROM servers
GROUP BY environment
HAVING COUNT(*) > 2;
-- Environnements avec plus de 20 Go de RAM totale
SELECT environment, SUM(ram_gb) AS total_ram
FROM servers
GROUP BY environment
HAVING SUM(ram_gb) > 20;
WHERE + HAVING combinés
-- Parmi les serveurs actifs, quels envs ont 2+ serveurs ?
SELECT environment,
COUNT(*) AS running_count,
ROUND(AVG(cpu_cores), 1) AS avg_cpus
FROM servers
WHERE status = 'running' -- filtre les lignes
GROUP BY environment
HAVING COUNT(*) >= 2 -- filtre les groupes
ORDER BY running_count DESC;
⚠️ L’ordre d’exécution SQL n’est pas l’ordre d’écriture. SQL exécute : FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT. C’est pour ça qu’un alias défini dans SELECT n’est pas utilisable dans WHERE — le WHERE s’exécute avant.
Cas entreprise : tableau de bord des déploiements
Un SRE gère des centaines de déploiements par semaine. Sans SQL, il ouvre des dashboards. Avec SQL, il crée ses propres analyses en temps réel.
-- Table deployments : deploy_id, service, environment,
-- version, deployed_by, deploy_time, status, duration_sec
-- Les 10 derniers déploiements
SELECT service, environment, version, deploy_time, status
FROM deployments
ORDER BY deploy_time DESC
LIMIT 10;
-- Déploiements par service ce mois, avec taux d'échec
SELECT service,
COUNT(*) AS total,
COUNT(CASE WHEN status = 'failed' THEN 1 END) AS failures,
ROUND(
100.0 * COUNT(CASE WHEN status = 'failed' THEN 1 END) / COUNT(*), 1
) AS failure_rate
FROM deployments
WHERE deploy_time >= '2026-03-01'
GROUP BY service
ORDER BY failure_rate DESC;
-- Durée moyenne par environnement (succès uniquement)
SELECT environment,
ROUND(AVG(duration_sec), 0) AS avg_duration,
MIN(duration_sec) AS fastest,
MAX(duration_sec) AS slowest
FROM deployments
WHERE status = 'success'
GROUP BY environment;
-- Services "bruyants" : plus de 5 échecs depuis janvier
SELECT service, COUNT(*) AS failures
FROM deployments
WHERE status = 'failed' AND deploy_time >= '2026-01-01'
GROUP BY service
HAVING COUNT(*) > 5
ORDER BY failures DESC;
🎯 La requête avec CASE WHEN dans un COUNT est un pattern essentiel. Elle permet de calculer des taux (succès, échec, conversion) en une seule passe. Tu la retrouveras partout en analytics.
Pièges et bonnes pratiques
⚠️ Les erreurs classiques à éviter :
LIMITsansORDER BY— Résultats imprévisibles. Toujours trier avant de limiter.GROUP BYsans toutes les colonnes — Chaque colonne duSELECTnon agrégée doit être dans leGROUP BY. PostgreSQL est strict là-dessus (MySQL moins, ce qui cause des bugs silencieux).WHEREavec une agrégation —WHERE COUNT(*) > 5ne compile pas. C’estHAVING COUNT(*) > 5.OFFSETélevé sur de grosses tables —OFFSET 100000force PostgreSQL à scanner 100 000 lignes pour les ignorer. Pour la pagination performante, utilise un curseur basé sur l’ID :WHERE server_id > 100000 LIMIT 10.- Oublier
ROUNDsur les moyennes —AVGretourne souvent 15 décimales. UnROUND(AVG(col), 1)rend le résultat lisible.
💡 Astuce pro : utilise \x dans psql pour activer l’affichage étendu quand tu as beaucoup de colonnes. Chaque colonne s’affiche sur sa propre ligne — bien plus lisible.
Résumé
🔥 Ce qu’on a couvert : ORDER BY pour trier les résultats (toujours explicite !), LIMIT / OFFSET pour la pagination, les fonctions d’agrégation (COUNT, SUM, AVG, MIN, MAX) pour analyser les données, GROUP BY pour regrouper, et HAVING pour filtrer les groupes après agrégation.
L’ordre d’exécution SQL (FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT) explique pourquoi certaines syntaxes marchent et d’autres non. Retiens-le — ça t’évitera des heures de debugging.
💡 À retenir :
WHEREfiltre les lignes,HAVINGfiltre les groupes. Si tu confonds les deux, PostgreSQL te le dira clairement. C’est la distinction fondamentale de ce chapitre.
Contenu réservé aux abonnés
Ce chapitre fait partie de la formation complète. Abonne-toi pour débloquer tous les contenus.
Débloquer pour 29 CHF/moisLe chapitre 1 de chaque formation est gratuit.
Série pas encore débloquée
Termine la série prérequise d'abord pour accéder à ce contenu.
Aller à la série prérequiseSérie : Apprendre SQL
2 / 6Sur cette page
Articles liés
Pourquoi SQL ? Les bases de données expliquées
Découvre ce qu'est SQL, les bases de données relationnelles, les SGBD, les propriétés ACID, les types de données, et écris tes premières requêtes SELECT et WHERE.
Les jointures : combiner les données
Maîtrise les jointures SQL (INNER, LEFT, RIGHT, FULL, CROSS JOIN) et les sous-requêtes pour combiner et croiser les données entre tables.
Administration : users, permissions, backup
CREATE, ALTER, DROP, INSERT, UPDATE, DELETE et contraintes SQL (PK, FK, UNIQUE, CHECK). Tout pour manipuler la structure et les données d'une base.