Pour construire efficacement des agrégations avec filtrage par "niveaux" (par exemple, d'abord filtrer, puis faire des sommes par groupes, puis sur l'ensemble), on utilise des fonctions de fenêtre (OVER()) et des GROUP BY imbriqués.
Exemple : Trouvons la somme maximale de commandes par manager, mais seulement parmi les commandes avec le statut 'paid', puis affichons le nom du manager avec le maximum absolu parmi tous.
WITH PaidOrders AS ( SELECT ManagerID, SUM(OrderAmount) AS TotalPaid FROM Orders WHERE Status = 'paid' GROUP BY ManagerID ), WithMax AS ( SELECT *, MAX(TotalPaid) OVER() AS MaxTotalPaid FROM PaidOrders ) SELECT ManagerID, TotalPaid FROM WithMax WHERE TotalPaid = MaxTotalPaid;
Cette approche (CTE + fonctions de fenêtre) permet de réaliser un filtrage et une agrégation à plusieurs niveaux.
Piège : "Quelle est la différence entre l'exécution du filtre WHERE avant le regroupement (GROUP BY) et l'application de HAVING après ? Quelles conséquences cela peut-il avoir sur les rapports ?"
Réponse : WHERE rejette les lignes encore avant le regroupement, c'est-à-dire qu'il donne un ensemble d'entrée strict. HAVING filtre les groupes agrégés — donc, il peut temporairement "laisser" des lignes superflues si le filtre n'est pas logiquement cohérent. Un mauvais placement du filtre entraîne souvent une erreur dans les agrégats finaux ou des résultats erronés dans les rapports.
-- Nous obtenons la somme uniquement pour 'paid', via WHERE SELECT ManagerID, SUM(OrderAmount) FROM Orders WHERE Status = 'paid' GROUP BY ManagerID; -- Ou nous calculons les sommes pour tous, puis nous coupons avec HAVING SELECT ManagerID, SUM(OrderAmount) FROM Orders GROUP BY ManagerID HAVING SUM(OrderAmount) > 1000;
Histoire
Projet : Rapports de vente, audit de vérification.
Erreur : Le développeur a appliqué HAVING Status='paid' au lieu de WHERE, les agrégats incluaient incorrectement des commandes non payées, ce qui a faussé le calcul des KPI annuels du personnel.
Histoire
Projet : Analyse bancaire.
Erreur : Une fonction de fenêtre a été tentée d'appliquer à une agrégation complexe sans PARTITION BY, ce qui a entraîné des agrégats calculés sur l'ensemble de la table au lieu du groupe. Le budget du département a été calculé de manière incorrecte — il a fallu le restaurer manuellement.
Histoire
Projet : Magasin en ligne, statistiques de commandes.
Erreur : L'imbrication des fonctions de fenêtre dans une sous-requête n'a pas été prise en compte lors de l'optimisation — cela a conduit à un traitement multiple des données, la requête est devenue 20 fois plus lente qu'avec simplement double GROUP BY.