📊 Fonctions d'agrégation

Les fonctions d'agrégation calculent une valeur à partir d'un ensemble de lignes. Elles s'utilisent dans le SELECT ou le HAVING.

FonctionDescriptionExemple
COUNT(*)Nombre de lignes (inclut NULL)COUNT(*)
COUNT(col)Lignes non-NULL de la colonneCOUNT(email)
SUM(col)SommeSUM(total)
AVG(col)Moyenne (ignore NULL)AVG(prix)
MIN(col)Valeur minimaleMIN(prix)
MAX(col)Valeur maximaleMAX(date_commande)
-- Sans GROUP BY : agrège toute la table
SELECT
  COUNT(*)                    AS nb_produits,
  ROUND(AVG(prix), 2)         AS prix_moyen,
  MIN(prix)                   AS prix_min,
  MAX(prix)                   AS prix_max,
  ROUND(SUM(prix * stock), 2) AS valeur_stock
FROM produits;

📦 GROUP BY

GROUP BY regroupe les lignes ayant la même valeur dans une ou plusieurs colonnes. Les fonctions d'agrégation s'appliquent ensuite à chaque groupe.

-- Nombre de produits par catégorie
SELECT categorie_id, COUNT(*) AS nb_produits
FROM produits
GROUP BY categorie_id;

-- Avec JOIN pour afficher le nom de la catégorie
SELECT c.nom AS categorie, COUNT(p.id) AS nb, ROUND(AVG(p.prix), 2) AS prix_moyen
FROM categories c
LEFT JOIN produits p ON c.id = p.categorie_id
GROUP BY c.id, c.nom
ORDER BY nb DESC;

-- Chiffre d'affaires par mois
SELECT
  YEAR(date_commande)  AS annee,
  MONTH(date_commande) AS mois,
  COUNT(*)             AS nb_commandes,
  SUM(total)           AS ca
FROM commandes
WHERE statut != 'annulee'
GROUP BY YEAR(date_commande), MONTH(date_commande)
ORDER BY annee, mois;
En mode ONLY_FULL_GROUP_BY (activé par défaut depuis MySQL 5.7), toutes les colonnes du SELECT doivent soit être dans le GROUP BY, soit être dans une fonction d'agrégation.

🔽 HAVING — Filtrer les groupes

HAVING filtre les groupes après l'agrégation, comme WHERE filtre les lignes avant.

-- Catégories avec plus de 2 produits
SELECT categorie_id, COUNT(*) AS nb
FROM produits
GROUP BY categorie_id
HAVING nb > 2;

-- Clients avec un total d'achats > 500€
SELECT cl.nom, SUM(co.total) AS total
FROM clients cl
JOIN commandes co ON cl.id = co.client_id
GROUP BY cl.id, cl.nom
HAVING total > 500
ORDER BY total DESC;

-- WHERE + HAVING combinés
SELECT c.nom, COUNT(p.id) AS nb, AVG(p.prix) AS moy
FROM categories c
JOIN produits p ON c.id = p.categorie_id
WHERE p.stock > 0            -- filtre AVANT le regroupement
GROUP BY c.id, c.nom
HAVING moy > 50              -- filtre APRÈS le regroupement
ORDER BY moy DESC;

📋 Ordre des clauses SQL

L'ordre des clauses est fixe et ne peut pas être changé :

SELECT colonnes, agrégats, alias FROM table JOIN autre_table ON condition WHERE filtre_lignes_individuelles GROUP BY colonnes_de_regroupement HAVING filtre_groupes ORDER BY colonne ASC|DESC LIMIT n OFFSET m

📅 Fonctions de date

-- Dates actuelles
SELECT NOW(),         -- 2024-01-15 10:30:00
       CURDATE(),     -- 2024-01-15
       CURTIME();     -- 10:30:00

-- Extraction
SELECT YEAR(created_at), MONTH(created_at), DAY(created_at);
SELECT DAYNAME(NOW()),    -- lundi / Monday selon la locale
       MONTHNAME(NOW());

-- Formatage pour l'affichage
SELECT DATE_FORMAT(created_at, '%d/%m/%Y') AS date_fr FROM commandes;
SELECT DATE_FORMAT(created_at, '%d %M %Y') AS date_longue FROM commandes;

-- Calculs
SELECT DATE_ADD(NOW(), INTERVAL 30 DAY);   -- dans 30 jours
SELECT DATE_SUB(NOW(), INTERVAL 1 YEAR);   -- il y a 1 an
SELECT DATEDIFF('2024-12-31', '2024-01-01'); -- 364 jours

-- Requêtes fréquentes
SELECT * FROM commandes WHERE date_commande >= NOW() - INTERVAL 7 DAY;
SELECT * FROM commandes WHERE MONTH(date_commande) = MONTH(NOW())
  AND YEAR(date_commande) = YEAR(NOW());

📝 Fonctions de chaîne utiles

SELECT CONCAT(nom, ' ', prenom)   AS nom_complet FROM employes;
SELECT CONCAT_WS(', ', nom, ville) AS adresse     FROM clients;
SELECT UPPER(nom), LOWER(email)   FROM clients;
SELECT LENGTH('MySQL')            -- 5
SELECT CHAR_LENGTH('été')         -- 3 (caractères, pas octets)
SELECT LEFT(nom, 3)               -- 3 premiers caractères
SELECT RIGHT(email, 10)           -- 10 derniers caractères
SELECT TRIM('  espaces  ')        -- 'espaces'
SELECT REPLACE(nom, 'é', 'e')     FROM clients;
SELECT LPAD(id, 6, '0')           -- 000042 (padding gauche)

🔗 GROUP_CONCAT

Agrège les valeurs d'un groupe en une seule chaîne.

-- Liste des produits par catégorie
SELECT c.nom AS categorie,
       GROUP_CONCAT(p.nom ORDER BY p.nom SEPARATOR ', ') AS produits
FROM categories c
JOIN produits p ON c.id = p.categorie_id
GROUP BY c.id, c.nom;

-- Avec DISTINCT pour éviter les doublons
SELECT client_id,
       GROUP_CONCAT(DISTINCT statut ORDER BY statut) AS statuts
FROM commandes
GROUP BY client_id;