ProgrammationAnalyste SQL

Comment implémenter une agrégation efficace avec filtrage par couches à l'aide de fonctions de fenêtre et de regroupements en SQL ? Quelles sont les différences entre les approches et quelles erreurs les développeurs commettent-ils souvent ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

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.

  • Regroupement via GROUP BY n'agrège que les champs sélectionnés ; il est possible d'exclure l'influence de lignes "étrangères" uniquement par un filtre préalable (WHERE).
  • Les fonctions de fenêtre permettent de calculer des agrégats sur des fragments de données spécifiques, en appliquant des filtres sur le jeu de résultats (par exemple, seulement parmi les lignes du même groupe).

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.

Question piège.

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;

Exemples d'erreurs réelles en raison de l'ignorance des subtilités du sujet.


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.