Retour à la liste des articles Articles
19 minutes de lecture

Fonctions GROUP BY et Aggregate : Vue d'ensemble

Les fonctions GROUP BY et aggregate de SQL sont essentielles pour l'agrégation des données, l'analyse des données et la création de rapports. Explorons-les ensemble !

En SQL, les fonctions GROUP BY et d'agrégation sont l'une des fonctionnalités les plus populaires du langage. L'agrégation de données est essentielle pour l'analyse des données et la création de rapports ; pour donner un sens à toutes les données d'un ensemble de données, il est souvent nécessaire de les agréger.

Mais qu'est-ce que l'agrégation de données ? En termes simples, il s'agit de regrouper des données sur la base de valeurs communes et d'effectuer un calcul pour chaque groupe de données. Par exemple, vous pouvez regrouper une liste de chiens en fonction de leur race, puis utiliser un calcul pour déterminer la taille moyenne de chaque race. Cette tâche est rendue possible par la clause GROUP BY et la fonction d'agrégation AVG().

Si vous avez besoin de rafraîchir vos connaissances sur GROUP BY, notre cours est idéal. SQL pour les débutants cours est idéal. Il comporte 129 exercices interactifs que vous pouvez terminer en 10 heures environ. Il couvre des sujets tels que le filtrage des données, l'utilisation d'opérateurs logiques, la jointure et l'utilisation d'opérateurs d'ensemble.

Syntaxe de base de GROUP BY avec agrégats

GROUP BY Le groupe BY est une clause de SQL qui permet de regrouper les données ayant les mêmes valeurs. Le regroupement se fait par colonne(s), toutes les lignes ayant la même valeur dans cette colonne appartenant à un groupe. Vous pouvez ensuite effectuer des calculs récapitulatifs - tels que le comptage, la somme ou la moyenne des valeurs - pour chaque groupe. Par exemple, vous pouvez utiliser GROUP BY pour calculer le nombre d'employés dans un service, le salaire total ou le salaire moyen par service, etc.

La syntaxe de GROUP BY avec une fonction d'agrégation est la suivante :

SELECT column1, 
        column2, 
        ..., 
        aggregate_function(column_name)
FROM table_name
WHERE filtering_condition
GROUP BY column1, column2, …
HAVING filtering_condition;

La fonction d'agrégation est écrite dans l'instruction SELECT, et le résultat de la fonction est affiché dans une colonne supplémentaire.

La clause GROUP BY contient les colonnes par lesquelles vous souhaitez que votre résultat soit groupé. Cette clause est souvent utilisée avec les clauses WHERE et HAVING pour le filtrage. Dans la syntaxe, WHERE vient avant GROUP BY, tandis que HAVING vient après. (Je reviendrai sur ces deux clauses plus tard.) Par ailleurs, vos données contiendront parfois NULLs, et vous serez donc intéressé par la façon dont GROUP BY traite les NULL.

Un exemple de GROUP BY en action est présenté dans le GIF suivant.

Comment fonctionne le GROUP BY en SQL

Cet exemple de base regroupe les données par réalisateur et indique le nombre de films réalisés par chacun d'entre eux.

Fonctions d'agrégation SQL

Les fonctions agrégées de SQL sont utilisées lorsque vous souhaitez effectuer des calculs sur des données et renvoyer une valeur unique.

Les fonctions agrégées les plus courantes de SQL sont les suivantes :

  • COUNT() - Compte les lignes de la colonne indiquée.
  • SUM() - Renvoie la somme de toutes les valeurs.
  • AVG () - Calcule la moyenne d'un groupe de valeurs.
  • MIN() - Renvoie le minimum (la plus petite valeur) des valeurs données.
  • MAX() - Renvoie le maximum (la valeur la plus élevée) des valeurs données.

Consultez nos guides sur l'utilisation de ces fonctions pour calculer des agrégats pour l'ensemble du tableau :

Il est important de noter que la fonction COUNT() a plusieurs variantes d'utilisation :

  • COUNT(*) compte toutes les lignes d'un ensemble de résultats, y compris les valeurs NULL et les doublons.
  • COUNT(expression) compte les valeurs non NULL dans un ensemble de résultats.
  • COUNT(DISTINCT) compte les valeurs distinctes et ignore les doublons.

Pour plus de détails, consultez notre guide Quelle est la différence entre COUNT(*), COUNT(1), COUNT(column) et COUNT(DISTINCT) ?

Utilisation de GROUP BY avec les fonctions agrégées de SQL

J'utiliserai le tableau albums pour montrer comment les fonctions agrégées et GROUP BY fonctionnent ensemble. Le script de création de la table se trouve ici.

Cette table contient des données sur les albums musicaux. Voici un aperçu de la situation :

idartistalbumrelease_yearlengthlabel
1Grant GreenThe Latin Bit19630:38:56Blue Note Records
2AC/DCHigh Voltage19760:44:23Atlantic Records
3Brother Jack McDuffTo Seek a New Home19700:33:12Blue Note Records
4Grant GreenGreen Is Beautiful19700:37:33Blue Note Records
5Wayne ShorterMoto Grosso Feio19740:42:22Blue Note Records

Exemple 1 : COUNT() avec GROUP BY

Voici un exemple de code qui compte le nombre d'albums par étiquette :

SELECT label,
	 COUNT(*) AS number_of_albums
FROM albums
GROUP BY label; 

Je sélectionne l'étiquette et j'utilise COUNT(*) pour trouver le nombre d'albums. L'astérisque (*) est un raccourci pour compter toutes les lignes. Lorsque je regroupe les résultats par étiquette, COUNT() affiche le nombre d'albums par étiquette.

Voici le résultat :

labelnumber_of_albums
Atlantic Records13
Blue Note Records12
Stax Records14

Pour en savoir plus :

Exemple 2 : SUM() avec GROUP BY

Le code suivant additionne les longueurs des albums pour afficher le total de la musique disponible par artiste :

SELECT artist,
	 SUM(length) AS total_music_available
FROM albums
GROUP BY artist;

La fonction SUM() est appliquée à la colonne length et le résultat est ensuite regroupé par artiste.

Voici le résultat du code :

artisttotal_music_available
Isaac Hayes6:30:02
Otis Redding1:34:09
Brother Jack McDuff1:58:11
Aretha Franklin1:47:07
Grant Green3:10:11
John Prine1:21:57
Led Zeppelin3:32:07
Wayne Shorter2:38:02
Albert King3:08:28
AC/DC2:05:23

Pour en savoir plus :

Exemple 3 : AVG() avec GROUP BY

Ce code calcule la durée moyenne des albums de chaque artiste :

SELECT artist,
	 AVG(length) AS average_album_length
FROM albums
GROUP BY artist; 

Pour obtenir le résultat souhaité, vous devez utiliser AVG() sur la colonne length et grouper le résultat par artist.

Voici à quoi ressemble le résultat :

artistaverage_album_length
Isaac Hayes1:05:00
Otis Redding0:31:23
Brother Jack McDuff0:39:24
Aretha Franklin0:35:42
Grant Green0:38:02
John Prine0:40:59
Led Zeppelin0:42:25
Wayne Shorter0:39:31
Albert King0:37:42
AC/DC0:41:48

Pour en savoir plus :

Exemple 4 : MIN() et MAX() avec GROUP BY

Trouvons la longueur d'album la plus courte et la plus longue pour chaque année :

SELECT release_year,
	 MIN(length) AS minimum_album_length,
	 MAX(length) AS maximum_album_length
FROM albums
GROUP BY release_year
ORDER BY release_year; 

Comme dans les exemples précédents, les fonctions d'agrégation sont utilisées sur la colonne length; MIN() pour l'album le plus court et MAX() pour l'album le plus long.

Les résultats sont regroupés par année de sortie.

J'ai également ajouté la clause ORDER BY pour trier les résultats de l'année la plus ancienne à l'année la plus récente afin de les rendre plus lisibles.

Voici le résultat du code :

release_yearminimum_album_lengthmaximum_album_length
19620:34:490:34:49
19630:38:560:38:56
19640:30:170:30:17
19650:32:220:42:45
19670:32:510:41:08
19680:29:300:29:30
19690:31:300:46:00
19700:33:120:43:04
19710:42:371:33:38
19720:37:500:44:46
19730:40:571:43:10
19740:42:220:46:00
19760:39:590:44:23
19770:41:010:41:01

Pour en savoir plus :

Techniques avancées de GROUP BY

La section précédente traitait des bases de l'utilisation des fonctions agrégées SQL et de GROUP BY. Ces bases étant posées, nous pouvons maintenant explorer quelques techniques avancées de GROUP BY.

Filtrage des résultats agrégés avec HAVING

Pour filtrer les résultats agrégés, vous devez utiliser la clause HAVING. Sa syntaxe est illustrée ci-dessous :

SELECT column1, 
       column2, 
       ..., 
       aggregate_function(column_name)
FROM table_name
GROUP BY column1, column2, …
HAVING filtering_condition;

HAVING compare les valeurs agrégées à la condition de filtrage et renvoie uniquement les valeurs qui satisfont à cette condition. Pour en savoir plus, consultez notre article sur la clause HAVING.

Laissez-moi vous montrer un exemple. Le code suivant calcule la durée moyenne des albums par artiste, mais il n'affiche que ceux dont la durée moyenne est inférieure à 40 minutes.

SELECT artist,
	 AVG(length) AS average_album_length
FROM albums
GROUP BY artist
HAVING AVG(length) < '00:40:00';

J'ai utilisé la fonction AVG() de la même manière que précédemment. La clause HAVING est nouvelle. Pour filtrer les données de la manière voulue, j'ai écrit dans HAVING le même calcul de moyenne que celui qui apparaît dans SELECT. Ensuite, j'utilise l'opérateur de comparaison 'less than'(<) pour comparer chaque résultat groupé à une valeur (dans ce cas, 40 minutes). Cette valeur est placée entre guillemets simples (''). La valeur entre guillemets doit être écrite au format HH:MM:SS (heures:minutes:secondes) parce que les valeurs de la colonne length sont du type de données INTERVAL.

Voici le résultat :

artistaverage_album_length
Otis Redding0:31:23
Brother Jack McDuff0:39:24
Aretha Franklin0:35:42
Grant Green0:38:02
Wayne Shorter0:39:31
Albert King0:37:42

Le principe est le même quelle que soit la fonction d'agrégation que vous utilisez, mais voici les livres de recettes pour vous aider avec d'autres fonctions :

Regroupement par colonnes multiples

Jusqu'à présent, j'ai regroupé les données en fonction d'une seule colonne. Cependant, il est également possible de regrouper les données en fonction de deux colonnes ou plus.

Ce n'est pas compliqué : Il suffit d'énumérer toutes les colonnes de regroupement dans GROUP BY et de les séparer par des virgules.

Ce faisant, vous effectuez un regroupement en fonction des valeurs des colonnes, mais aussi en fonction de la combinaison des valeurs de toutes les colonnes de regroupement. Si vous avez la valeur A dans la colonne_1 et la valeur B dans la colonne_2, il s'agit d'un groupe. S'il y a, par exemple, des valeurs A dans la colonne_1 et des valeurs C dans la colonne_2, cela formera un autre groupe - bien que les valeurs de la colonne_1 soient les mêmes que dans l'exemple précédent.

Exemple

Le code ci-dessous indique le nombre d'albums de l'artiste et l'année de sortie :

SELECT artist,
	 release_year,
	 COUNT(*) AS number_of_albums
FROM albums
GROUP BY artist, release_year
ORDER BY artist, release_year;

J'utilise COUNT(*) pour trouver le nombre d'albums. Les résultats sont regroupés par artiste et année de sortie. Comme vous pouvez le voir, ce sont exactement les colonnes de GROUP BY et elles sont séparées par une virgule.

Pour rendre le résultat plus lisible, j'ai trié les données par artiste dans l'ordre alphabétique et de l'année de sortie la plus ancienne à la plus récente.

Voici l'aperçu de la sortie :

artistrelease_yearnumber_of_albums
AC/DC19762
AC/DC19771
Albert King19621
Albert King19671
Albert King19691
Albert King19721
Albert King19741
Aretha Franklin19671
Aretha Franklin19681
Aretha Franklin19721
Brother Jack McDuff19692
Brother Jack McDuff19701

Deux fonctions d'agrégation en une seule requête

Il est également possible d'écrire une requête comportant deux fonctions d'agrégation. Non, ce n'est pas ce que vous pensez : vous n'écrivez pas une fonction agrégée à l'intérieur d'une autre. Ce n'est pas possible en SQL.

Deux fonctions agrégées dans une même requête, cela peut vouloir dire deux choses :

  1. Approche simple : Utilisation de deux fonctions agrégées dans deux colonnes du même SELECT.
  2. Approche avancée : Utilisation du résultat d'une fonction agrégée dans une autre fonction agrégée.

Une requête, deux fonctions agrégées : L'approche simple

L'approche simple consiste à utiliser deux fonctions agrégées dans deux colonnes agrégées différentes sur le site SELECT. Il peut s'agir de la même fonction appliquée à des colonnes différentes, de fonctions différentes utilisées sur la même colonne ou de fonctions différentes utilisées sur des colonnes différentes. Cela n'a pas vraiment d'importance ; le fait est que vous avez deux agrégations dans une seule requête. Ces agrégations ne "communiquent" pas, c'est-à-dire qu'elles ne dépendent pas l'une de l'autre de quelque manière que ce soit.

Exemple

Dans l'exemple, j'utiliserai le tableau package_deliveries avec le script lié ici.

Le tableau contient des informations sur le nombre de colis livrés quotidiennement dans plusieurs villes.

Voici les six premières lignes du tableau :

iddate_of_deliverynumber_of_packagescity_of_deliverycountry_of_delivery
12024-03-0149KrakowPoland
22024-03-01528WarsawPoland
32024-03-01158GdanskPoland
42024-03-0128RijekaCroatia
52024-03-0197SplitCroatia
62024-03-0164ZagrebCroatia

Le code ci-dessous calcule le nombre total et le nombre moyen de colis par ville.

SELECT city_of_delivery,
	 SUM(number_of_packages) AS total_number_of_packages,
	 AVG(number_of_packages) AS average_number_of_packages
FROM package_deliveries
GROUP BY city_of_delivery;

Vous pouvez voir que la requête comporte deux agrégats : un avec SUM() et un avec AVG(). Le nombre de fonctions d'agrégat que vous écrivez dans la requête n'a pas vraiment d'importance. La seule chose importante est que chaque agrégat soit traité comme une ligne de code ou une colonne de sortie distincte.

Voici le résultat :

city_of_deliverytotal_number_of_packagesaverage_number_of_packages
Split531177.00
Izmir5,9361,978.67
Ankara9,1393,046.33
Gdansk712237.33
Rijeka627209.00
Zagreb930310.00
Istanbul13,8574,619.00
Krakow673224.33
Warsaw2,358786.00

Une requête, deux fonctions agrégées : L'approche avancée

Dans la version avancée, les agrégats "communiquent", c'est-à-dire que vous devez d'abord trouver une valeur agrégée, puis l'utiliser pour calculer une autre valeur agrégée. Généralement, cela se fait par le biais de sous-requêtes ou d'expressions de tableau communes (CTE).

Je vous montrerai l'utilisation des sous-requêtes dans l'exemple ci-dessous. Notre guide sur la combinaison de deux fonctions agrégées dans GROUP BY couvre les deux approches.

Exemple

Le code suivant renvoie le nombre quotidien moyen de colis livrés dans chaque pays :

SELECT country_of_delivery,
	 AVG(pd.daily_number_of_packages) AS average_daily_number_of_packages
FROM (SELECT date_of_delivery, 
	       country_of_delivery,
	 	 SUM(number_of_packages) AS daily_number_of_packages
	FROM package_deliveries
	GROUP BY date_of_delivery, country_of_delivery) AS pd
GROUP BY country_of_delivery;

Je dois d'abord trouver le nombre de colis livrés quotidiennement dans chaque pays, ce qui constitue la première agrégation. La deuxième agrégation utilise ce résultat et calcule la moyenne quotidienne par pays.

La première agrégation est écrite dans la sous-requête. Elle utilise la fonction SUM() et répertorie les colonnes date_of_delivery et country_of_delivery dans SELECT. Le résultat est groupé par les mêmes colonnes.

Je peux maintenant écrire la requête principale, en référençant dans AVG() la colonne daily_number_of_packages de la sous-requête. Je regroupe les résultats par pays et j'obtiens le nombre quotidien moyen de colis livrés pour chaque pays.

country_of_deliveryaverage_daily_number_of_packages
Turkey9,644.00
Croatia696.00
Poland1,247.67

GROUP BY avec des agrégats conditionnels

L'instruction CASE ou CASE WHEN étiquette les données en fonction de leurs valeurs. Cette instruction peut également être utilisée avec GROUP BY.

Le regroupement des données par agrégats conditionnels implique l'utilisation de CASE WHEN avec GROUP BY. Cependant - et c'est important - le CASE WHEN que vous écrivez dans SELECT doit également apparaître dans GROUP BY.

Exemple

En utilisant le tableau de l'exemple précédent, je peux écrire un code qui classe les pays en pays de l'UE et en pays hors UE et qui indique le nombre total de colis livrés pour chaque catégorie :

SELECT
  CASE 
   WHEN country_of_delivery = 'Turkey' THEN 'Non-EU'
   ELSE 'EU'
  END,
  SUM(number_of_packages) AS total_number_of_packages
FROM package_deliveries
GROUP BY CASE 
   WHEN country_of_delivery = 'Turkey' THEN 'Non-EU'
   ELSE 'EU'
  END;

L'énoncé CASE indique que la Turquie doit être classée dans la catégorie des pays non membres de l'UE. Cette condition est énoncée sur le site WHEN. La catégorie pour tous les autres pays est l'UE, ce qui est écrit dans ELSE.

La déclaration CASE commence par CASE (d'où son nom) et se termine par le mot-clé END.

J'utilise la fonction SUM() pour calculer le nombre total de paquets. Pour afficher cette valeur par catégorie, j'ai simplement copié l'intégralité de la déclaration CASE WHEN dans GROUP BY.

Voici le résultat :

casetotal_number_of_packages
Non-EU28,932
EU5,831

Si vous avez besoin de plus d'exemples pour bien comprendre, lisez l'un de nos guides :

Extensions de GROUP BY : ROLLUP, CUBE, ENSEMBLES DE REGROUPEMENT

Les trois extensions SQL GROUP BY sont les suivantes

  • ROLLUP - Crée une ligne de résumé pour les groupes énumérés dans GROUP BY.
  • CUBE - Crée des sous-totaux pour toutes les combinaisons des groupes figurant dans GROUP BY.
  • GROUPING SETS - Agrégation des résultats à plusieurs niveaux.

Dans l'exemple, je vous montrerai comment fonctionnent les GROUPING SETS. Pour en savoir plus sur le fonctionnement des deux autres extensions, consultez notre guide sur les extensions GROUP BY.

Exemple

Le code suivant renvoie le nombre de colis livrés par pays et par date :

SELECT country_of_delivery,
	 date_of_delivery,
	 SUM(number_of_packages) AS total_number_of_packages
FROM package_deliveries
GROUP BY GROUPING SETS(country_of_delivery, date_of_delivery)
ORDER BY country_of_delivery, date_of_delivery;

Je commence par utiliser SUM() pour calculer le nombre de colis.

Dans GROUP BY, j'écris GROUPING SETS avec tous les niveaux d'agrégation entre parenthèses.

Le résultat montre le nombre de colis livrés par pays et par date de livraison :

country_of_deliverydate_of_deliverytotal_number_of_packages
CroatiaNULL2,088
PolandNULL3,743
TurkeyNULL28,932
NULL2024-03-012,730
NULL2024-03-0211,208
NULL2024-03-0320,825

Il peut être utile de considérer les ensembles de regroupement comme deux requêtes distinctes. La première requête regroupe par pays ...

SELECT country_of_delivery,
       NULL AS date_of_delivery,
       SUM(number_of_packages) AS total_number_of_packages
FROM package_deliveries
GROUP BY country_of_delivery
ORDER BY country_of_delivery;

... et renvoie les trois premières lignes de la sortie précédente :

country_of_deliverydate_of_deliverytotal_number_of_packages
CroatiaNULL2,088
PolandNULL3,743
TurkeyNULL28,932

La seconde requête regroupe les données par date de livraison ...

SELECT NULL AS country_of_delivery,
       date_of_delivery,
       SUM(number_of_packages) AS total_number_of_packages
FROM package_deliveries
GROUP BY date_of_delivery
ORDER BY date_of_delivery;

... et renvoie les trois autres lignes du résultat original :

country_of_deliverydate_of_deliverytotal_number_of_packages
NULL2024-03-012,730
NULL2024-03-0211,208
NULL2024-03-0320,825

En d'autres termes, si vous fusionnez ces deux requêtes de regroupement distinctes à l'aide de UNION...

SELECT country_of_delivery,
       NULL AS date_of_delivery,
       SUM(number_of_packages) AS total_number_of_packages
FROM package_deliveries
GROUP BY country_of_delivery

UNION 

SELECT NULL AS country_of_delivery,
       date_of_delivery,
       SUM(number_of_packages) AS total_number_of_packages
FROM package_deliveries
GROUP BY date_of_delivery
ORDER BY country_of_delivery, date_of_delivery;

... vous obtenez exactement le même résultat qu'avec GROUPING SETS.

country_of_deliverydate_of_deliverytotal_number_of_packages
CroatiaNULL2,088
PolandNULL3,743
TurkeyNULL28,932
NULL2024-03-012,730
NULL2024-03-0211,208
NULL2024-03-0320,825

Erreurs courantes lors de l'utilisation de GROUP BY

Confusion entre ORDER BY et GROUP BY

Il s'agit souvent de ne pas savoir ce que fait GROUP BY.

Permettez-moi de vous donner un exemple.

Supposons que vous souhaitiez trouver le nombre total de colis par pays de livraison.

Si vous ne connaissez pas GROUP BY, vous pouvez écrire une solution naïve en utilisant ORDER BY.

SELECT date_of_delivery,
	 city_of_delivery,
	 country_of_delivery
FROM package_deliveries
ORDER BY country_of_delivery;

Maintenant que vous avez trié les données par pays, comme le montre la capture d'écran ci-dessous, vous décidez d'additionner manuellement les valeurs pour obtenir le résultat par pays.

date_of_deliverycity_of_deliverycountry_of_delivery
2024-03-01RijekaCroatia
2024-03-01SplitCroatia
2024-03-01ZagrebCroatia
2024-03-02RijekaCroatia
2024-03-02SplitCroatia
2024-03-02ZagrebCroatia
2024-03-03ZagrebCroatia
2024-03-03SplitCroatia
2024-03-03RijekaCroatia
2024-03-01KrakowPoland
2024-03-01WarsawPoland

Mais pourquoi feriez-vous manuellement quelque chose que GROUP BY fait automatiquement ? Au lieu de classer les données par pays, vous devriez les regrouper par pays et utiliser SUM() pour additionner les données :

SELECT country_of_delivery,
	 SUM(number_of_packages) AS total_number_of_packages
FROM package_deliveries
GROUP BY country_of_delivery
ORDER BY country_of_delivery;

Vous obtiendrez immédiatement le résultat dont vous avez besoin :

country_of_deliverytotal_number_of_packages
Croatia2,088
Poland3,743
Turkey28,932

Pour en savoir plus sur les différences entre GROUP BY et ORDER BY et sur la manière d'utiliser GROUP BY et ORDER BY ensemble.

Confusion entre WHERE et HAVING

Une autre erreur fréquente consiste à essayer de filtrer des valeurs agrégées à l'aide de WHERE. Ce n'est pas possible - WHERE est utilisé pour filtrer les lignes individuelles avant l' agrégation. En revanche, HAVING sert à filtrer des groupes de lignes après l' agrégation.

Exemple

Si vous souhaitez obtenir le nombre moyen de colis livrés quotidiennement par ville et n'afficher que les villes ayant livré plus de 500 colis, vous pouvez décider d'écrire cette requête :

SELECT city_of_delivery,
	 AVG(number_of_packages) AS average_number_of_packages
FROM package_deliveries
WHERE AVG(number_of_packages) > 500
GROUP BY city_of_delivery;

Elle renverra une erreur car WHERE n'accepte pas de fonction d'agrégation en tant qu'argument. (Cela ne signifie pas que vous ne pouvez jamais utiliser WHERE avec GROUP BY; vous le pouvez, mais pas pour filtrer des groupes).

Dans ce cas, vous devez utiliser HAVING:

SELECT city_of_delivery,
	 AVG(number_of_packages) AS average_number_of_packages
FROM package_deliveries
GROUP BY city_of_delivery
HAVING AVG(number_of_packages) > 500;

Il s'agit de la même requête avec AVG() et GROUP BY. La seule différence est HAVING, où vous comparez le calcul de AVG() avec 500.

Le résultat n'affiche que les villes dont la moyenne quotidienne est supérieure à 500.

city_of_deliveryaverage_number_of_packages
Izmir1,978.67
Ankara3,046.33
Istanbul4,619.00
Warsaw786.00

Pour en savoir plus, consultez l'article HAVING vs WHERE.

Énumérer les colonnes non agrégées dans SELECT mais pas dans WHERE

La règle simple dont vous devez vous souvenir est que toute colonne non agrégée que vous écrivez dans SELECT doit également être incluse dans GROUP BY. Si vous ne le faites pas, la base de données ne saura pas quelle valeur afficher si plusieurs valeurs différentes se trouvent dans le même groupe.

Exemple

Par exemple, vous écrivez une requête censée calculer le nombre total de paquets par pays et par ville.

SELECT country_of_delivery,
       city_of_delivery,
	 SUM(number_of_packages) total_number_of_packages
FROM package_deliveries
GROUP BY country_of_delivery;

Bien sûr, vous avez le pays et la ville dans SELECT, mais vous avez oublié de mettre la ville dans GROUP BY. Cette requête ne s'exécutera pas. Elle renvoie une erreur. Bien que les messages soient formulés différemment dans PostgreSQL, Oracle et d'autres bases de données, le message est le même : la colonne city_of_delivery doit apparaître dans GROUP BY.

Même si elle s'exécutait, la base de données serait confuse. Elle penserait à peu près ceci : "Vous voulez afficher les villes, mais vous ne voulez pas grouper par ville ? Comment suis-je censé savoir quelle ville afficher dans le résultat alors que chaque pays en compte trois ? S'il vous plaît, mettez les villes dans GROUP BY pour que je puisse afficher chaque ville comme un groupe séparé."

Vous l'aidez donc en incluant la ville de livraison dans GROUP BY:

SELECT country_of_delivery,
       city_of_delivery,
	 SUM(number_of_packages) total_number_of_packages
FROM package_deliveries
GROUP BY country_of_delivery, city_of_delivery;

Oui, il s'agit d'un regroupement sur deux colonnes et vous avez déjà appris à le faire. Voici le résultat de la requête :

country_of_deliverycity_of_deliverytotal_number_of_packages
CroatiaZagreb930
CroatiaRijeka627
CroatiaSplit531
TurkeyIstanbul13,857
PolandWarsaw2,358
PolandKrakow673
TurkeyAnkara9,139
PolandGdansk712
TurkeyIzmir5,936

Autres erreurs

Il y a aussi d'autres erreurs, comme l'oubli de GROUP BY avec des fonctions agrégées ou le fait de ne pas grouper par une clé unique. Ces erreurs et bien d'autres sont abordées dans cet article sur les erreurs courantes de GROUP BY.

Autres ressources SQL GROUP BY

Après avoir lu cet aperçu de la clause SQL GROUP BY, vous devriez avoir une idée de ses utilisations et de ses défis. Mais si vous voulez maîtriser GROUP BY, vous devrez entrer dans les détails.

La meilleure façon de le faire est de consulter certains de nos cours et livres de cuisine. Voici quelques-unes de mes suggestions pour poursuivre votre apprentissage :

  • Création de rapports basiques en SQL - Ce cours de niveau intermédiaire se concentre sur les nuances de l'utilisation de GROUP BY - le regroupement par colonnes multiples, l'utilisation de HAVING, la combinaison de GROUP BY avec CASE WHEN, la différence entre COUNT(*) et COUNT(id), etc.
  • La pratique du SQL - Les cours de cette filière comportent des sections consacrées à différents sujets SQL, y compris de nombreux exercices pratiques sur GROUP BY.

N'oubliez pas non plus nos articles présentant des exemples GROUP BY. Deux de mes préférés sont La pratique du SQL: 10 exercices pratiques GROUP BY avec solutions détaillées et Top 9 SQL GROUP BY Interview Questions.

En outre, il existe une antisèche SQL pour l'analyse de données, qui comporte une section consacrée à GROUP BY.

Bon apprentissage !