Combien d’alertes critiques non acquittées ? Quel est le temps moyen de déploiement par service ? Quel serveur a le plus gros disque ? Toutes ces questions se résolvent en une seule requête SQL grâce aux fonctions d’agrégation (COUNT, SUM, AVG, MIN, MAX) combinées avec GROUP BY.
Au-delà de l’agrégation, SQL propose des dizaines de fonctions intégrées pour manipuler les chaînes, les dates et les nombres — directement dans vos requêtes, sans passer par un langage de programmation. Ce guide couvre les fonctions les plus utiles au quotidien, avec les particularités de SQLite et les différences avec PostgreSQL/MySQL.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Compter, sommer, moyenner avec
COUNT,SUM,AVG,MIN,MAX - Regrouper les résultats avec
GROUP BY - Filtrer les groupes avec
HAVING(distinct deWHERE) - Manipuler les chaînes :
UPPER,LOWER,TRIM,SUBSTR, concaténation avec|| - Travailler avec les dates :
date(),datetime(),strftime()en SQLite - Convertir et gérer les
NULL:CAST,COALESCE,NULLIF
Dans quel contexte ?
Section intitulée « Dans quel contexte ? »Les fonctions SQL sont utilisées constamment en administration :
- Compter les alertes par sévérité et par serveur
- Calculer le temps moyen de déploiement par service
- Trouver la date du dernier déploiement réussi pour chaque service
- Nettoyer des données (majuscules, espaces parasites) avant une migration
- Formater des dates pour un export CSV lisible par l’équipe
Ce guide ne couvre pas…
Section intitulée « Ce guide ne couvre pas… »- Les fonctions de fenêtrage (
ROW_NUMBER,RANK,LAG,LEAD) → voir le guide SQL avancé - Les jointures (
JOIN) → voir le guide Jointures et sous-requêtes - La création de fonctions personnalisées (
CREATE FUNCTION) → consultez la documentation de votre SGBD
Prérequis
Section intitulée « Prérequis »- Savoir écrire un
SELECT … WHERE(guide Syntaxe de base) - La base fil rouge
infra.dbchargée dans~/Projets/cours-sql - Comprendre les jointures (guide précédent) pour les exemples multi-tables
Les fonctions d’agrégation
Section intitulée « Les fonctions d’agrégation »Les fonctions d’agrégation calculent une seule valeur à partir de plusieurs lignes.
COUNT : compter les lignes
Section intitulée « COUNT : compter les lignes »-- Nombre total de serveursSELECT COUNT(*) FROM servers;
-- Nombre de serveurs actifsSELECT COUNT(*) FROM servers WHERE active = 1;COUNT(*) vs COUNT(colonne) vs COUNT(DISTINCT)
Section intitulée « COUNT(*) vs COUNT(colonne) vs COUNT(DISTINCT) »| Expression | Comportement |
|---|---|
COUNT(*) | Compte toutes les lignes (y compris celles avec des NULL) |
COUNT(email) | Compte les lignes où email n’est pas NULL |
COUNT(DISTINCT os) | Compte le nombre de valeurs uniques de os |
SELECT COUNT(*) AS total_users, COUNT(email) AS avec_email, COUNT(DISTINCT role) AS nb_rolesFROM users;SUM et AVG : somme et moyenne
Section intitulée « SUM et AVG : somme et moyenne »-- RAM totale de tous les serveurs de productionSELECT SUM(ram_gb) AS ram_totaleFROM serversWHERE environment = 'production' AND active = 1;
-- Durée moyenne de déploiement (en secondes)SELECT AVG(duration_seconds) AS duree_moyenneFROM deploymentsWHERE status = 'success';MIN et MAX : valeurs extrêmes
Section intitulée « MIN et MAX : valeurs extrêmes »-- Premier et dernier serveur crééSELECT MIN(created_at) AS premier, MAX(created_at) AS dernierFROM servers;
-- Disque le plus grandSELECT MAX(disk_gb) AS plus_gros_disque FROM servers;MIN et MAX fonctionnent aussi sur les chaînes (ordre alphabétique) et les dates.
Regrouper avec GROUP BY
Section intitulée « Regrouper avec GROUP BY »Principe : une ligne par groupe
Section intitulée « Principe : une ligne par groupe »GROUP BY divise les lignes en groupes selon une ou plusieurs colonnes, puis applique les fonctions d’agrégation sur chaque groupe :
-- Nombre de serveurs par environnementSELECT environment, COUNT(*) AS nb_serveursFROM serversWHERE active = 1GROUP BY environment;Résultat : une ligne par environment, avec le nombre de serveurs associé.
GROUP BY sur plusieurs colonnes
Section intitulée « GROUP BY sur plusieurs colonnes »-- Nombre d'alertes par serveur et par sévéritéSELECT server_id, severity, COUNT(*) AS nbFROM alertsGROUP BY server_id, severityORDER BY server_id, nb DESC;GROUP BY avec jointure
Section intitulée « GROUP BY avec jointure »Pour afficher le hostname au lieu de l’ID, combinez GROUP BY et JOIN :
SELECT sv.hostname, a.severity, COUNT(*) AS nb_alertesFROM alerts aINNER JOIN servers sv ON sv.id = a.server_idGROUP BY sv.hostname, a.severityORDER BY nb_alertes DESC;Pièges courants : colonnes non agrégées dans le SELECT
Section intitulée « Pièges courants : colonnes non agrégées dans le SELECT »Filtrer les groupes avec HAVING
Section intitulée « Filtrer les groupes avec HAVING »HAVING vs WHERE
Section intitulée « HAVING vs WHERE »| Clause | Filtre | Exécuté |
|---|---|---|
WHERE | Lignes individuelles avant le regroupement | Avant GROUP BY |
HAVING | Groupes après le regroupement | Après GROUP BY |
-- WHERE filtre les lignes AVANT le regroupementSELECT server_id, COUNT(*) AS nbFROM alertsWHERE severity = 'critical'GROUP BY server_id;
-- HAVING filtre les groupes APRÈS le regroupementSELECT server_id, COUNT(*) AS nbFROM alertsGROUP BY server_idHAVING COUNT(*) > 3;Exemple : groupes au-dessus d’un seuil
Section intitulée « Exemple : groupes au-dessus d’un seuil »-- Utilisateurs qui ont effectué plus de 3 déploiementsSELECT u.full_name, COUNT(*) AS nb_deployFROM deployments dINNER JOIN users u ON u.id = d.deployed_byGROUP BY u.full_nameHAVING COUNT(*) > 3ORDER BY nb_deploy DESC;Fonctions de manipulation de chaînes
Section intitulée « Fonctions de manipulation de chaînes »LENGTH, UPPER, LOWER, TRIM
Section intitulée « LENGTH, UPPER, LOWER, TRIM »SELECT LENGTH('bonjour'); -- 7SELECT UPPER('bonjour'); -- BONJOURSELECT LOWER('BONJOUR'); -- bonjourSELECT TRIM(' bonjour '); -- bonjourSELECT LTRIM(' bonjour'); -- bonjourSELECT RTRIM('bonjour '); -- bonjourSUBSTR, REPLACE, concaténation
Section intitulée « SUBSTR, REPLACE, concaténation »-- Extraire les 3 premiers caractères du hostnameSELECT SUBSTR(hostname, 1, 3) FROM servers;
-- Remplacer un domaine dans les emailsSELECT REPLACE(email, '@infra.local', '@newdomain.fr') FROM users WHERE email IS NOT NULL;En SQLite (et PostgreSQL), la concaténation utilise || :
SELECT username || ' (' || role || ')' AS display FROM users;-- Résultat : jdupont (admin)Pattern matching au-delà de LIKE
Section intitulée « Pattern matching au-delà de LIKE »SQLite ne dispose pas de ILIKE (PostgreSQL) ni de REGEXP natif. LIKE est insensible à la casse pour les lettres ASCII (A-Z) par défaut en SQLite :
-- Fonctionne en SQLite : LIKE est case-insensitive pour l'ASCIISELECT * FROM users WHERE email LIKE '%@infra.local';Fonctions de dates et heures
Section intitulée « Fonctions de dates et heures »SQLite stocke les dates comme du texte au format ISO 8601 ('2026-04-13 08:30:00'). Les comparaisons avec <, >, BETWEEN fonctionnent correctement sur ce format. Les fonctions de date de SQLite sont différentes de celles de PostgreSQL et MySQL.
Date et heure courantes
Section intitulée « Date et heure courantes »SELECT date('now'); -- 2026-04-13SELECT time('now'); -- 08:30:00SELECT datetime('now'); -- 2026-04-13 08:30:00Extraire une partie de la date avec strftime
Section intitulée « Extraire une partie de la date avec strftime »SELECT strftime('%Y', created_at) AS annee, strftime('%m', created_at) AS mois, strftime('%w', created_at) AS jour_semaineFROM servers;Formats courants : %Y (année), %m (mois), %d (jour), %H (heure), %M (minute), %S (seconde), %w (jour de la semaine 0=dimanche).
Arithmétique de dates (modificateurs)
Section intitulée « Arithmétique de dates (modificateurs) »SQLite utilise des modificateurs au lieu de INTERVAL :
-- Alertes de moins de 24 heuresSELECT * FROM alertsWHERE created_at > datetime('now', '-24 hours');
-- Serveurs créés dans les 30 derniers joursSELECT hostname, created_at FROM serversWHERE created_at > date('now', '-30 days');
-- Dans 7 joursSELECT date('now', '+7 days');Formater une date
Section intitulée « Formater une date »-- SQLite : strftime avec le format souhaitéSELECT strftime('%d/%m/%Y %H:%M', created_at) AS date_frFROM servers;-- Résultat : 15/03/2025 09:00Fonctions numériques
Section intitulée « Fonctions numériques »SELECT ROUND(3.14159, 2); -- 3.14SELECT ROUND(ram_gb * 1.0 / cpu_cores, 1) AS ram_par_core FROM servers;
SELECT ABS(-42); -- 42SELECT MAX(disk_gb) % 100 FROM servers; -- moduloFonctions de conversion
Section intitulée « Fonctions de conversion »-- SQL standard (fonctionne partout)SELECT CAST('42' AS INTEGER);SELECT CAST(ram_gb AS REAL) / cpu_cores FROM servers;COALESCE : remplacer les NULL
Section intitulée « COALESCE : remplacer les NULL »COALESCE renvoie la première valeur non NULL parmi ses arguments :
-- Afficher "non renseigné" si l'email est NULLSELECT username, COALESCE(email, 'non renseigné') AS email FROM users;
-- Afficher "Aucune note" pour les serveurs sans noteSELECT hostname, COALESCE(notes, 'Aucune note') AS notes FROM servers;
-- Traiter les NULL comme 0 dans un calculSELECT SUM(COALESCE(duration_seconds, 0)) FROM deployments;NULLIF : comparer deux valeurs
Section intitulée « NULLIF : comparer deux valeurs »NULLIF(a, b) renvoie NULL si a = b, sinon renvoie a. Utile pour éviter les divisions par zéro :
-- Taux de succès par service (évite la division par zéro)SELECT s.name, COUNT(CASE WHEN d.status = 'success' THEN 1 END) * 100.0 / NULLIF(COUNT(*), 0) AS taux_succesFROM deployments dINNER JOIN services s ON s.id = d.service_idGROUP BY s.name;Exercice pratique
Section intitulée « Exercice pratique »Ouvrez sqlite3 infra.db et pratiquez :
-
Comptez le nombre d’alertes par sévérité.
SELECT severity, COUNT(*) AS nbFROM alertsGROUP BY severityORDER BY nb DESC; -
Calculez la durée moyenne de déploiement par utilisateur, uniquement pour ceux qui ont plus de 3 déploiements réussis.
SELECT u.full_name, AVG(d.duration_seconds) AS duree_moyenne, COUNT(*) AS nbFROM deployments dINNER JOIN users u ON u.id = d.deployed_byWHERE d.status = 'success'GROUP BY u.full_nameHAVING COUNT(*) > 3ORDER BY duree_moyenne; -
Listez les serveurs créés ces 12 derniers mois avec la date formatée en français.
SELECT hostname, os,strftime('%d/%m/%Y', created_at) AS date_creationFROM serversWHERE created_at > date('now', '-12 months')ORDER BY created_at DESC; -
Remplacez les emails NULL par « non renseigné » et les notes NULL par « Aucune note ».
SELECT username,COALESCE(email, 'non renseigné') AS emailFROM users;SELECT hostname,COALESCE(notes, 'Aucune note') AS notesFROM servers; -
Calculez la RAM totale et le nombre de cœurs par datacenter pour les serveurs actifs.
SELECT datacenter,COUNT(*) AS nb_serveurs,SUM(ram_gb) AS ram_totale,SUM(cpu_cores) AS cores_totauxFROM serversWHERE active = 1GROUP BY datacenter;
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
column must appear in GROUP BY | Colonne dans le SELECT sans agrégation ni GROUP BY | Ajoutez la colonne au GROUP BY ou entourez-la d’une fonction d’agrégation |
AVG donne un résultat inattendu | Les NULL sont ignorés par AVG | Utilisez COALESCE(col, 0) avant l’agrégation si les NULL doivent compter comme 0 |
| Division par zéro | Le dénominateur est 0 | Utilisez NULLIF(denominateur, 0) |
HAVING ne filtre pas | Vous avez mis la condition dans WHERE au lieu de HAVING | Déplacez les conditions sur des agrégats dans HAVING |
strftime renvoie NULL | La date n’est pas au format ISO 8601 | Vérifiez que les données sont au format YYYY-MM-DD HH:MM:SS |
À retenir
Section intitulée « À retenir »COUNT,SUM,AVG,MIN,MAXcalculent une valeur par groupe de lignesGROUP BYdéfinit les groupes — toute colonne duSELECTdoit y figurer ou être dans une agrégationWHEREfiltre avant le regroupement,HAVINGfiltre aprèsCOALESCEremplace lesNULLpar une valeur par défaut — indispensable pour les calculsNULLIFprotège contre les divisions par zéro- La concaténation utilise
||en SQLite/PostgreSQL etCONCAT()en MySQL - Les fonctions de dates SQLite utilisent
strftime(),date(),datetime()avec des modificateurs ('-30 days','+1 hour')