🧚 Écoute ! Beekeeper Studio est une interface de base de données rapide, moderne et open source Télécharger
8 janvier 2026 Par Matthew Rathbone

GROUP BY rassemble en groupes les lignes qui partagent une valeur, pour que les fonctions d’agrégation comme COUNT, SUM et AVG renvoient un résultat par groupe au lieu d’un seul pour toute la table. Les exemples fonctionnent sous PostgreSQL, MySQL, SQLite et SQL Server.

Comment utiliser GROUP BY

Indique la colonne de regroupement après GROUP BY, et place chaque autre colonne sélectionnée dans une fonction d’agrégation : COUNT, SUM, AVG, MIN ou MAX. Tu obtiens une ligne par valeur distincte :

SELECT group_column, AGGREGATE(value_column)
FROM table_name
GROUP BY group_column;
-- Input: scores
-- player | team | points
-- -------+------+-------
-- Ana    | Red  | 12
-- Ben    | Blue | 9
-- Cleo   | Red  | 7
-- Dev    | Blue | 15
-- Eli    | Red  | 4

SELECT team, SUM(points) AS total_points, COUNT(*) AS players
FROM scores
GROUP BY team;

-- Output:
-- team | total_points | players
-- -----+--------------+--------
-- Red  | 23           | 3
-- Blue | 24           | 2

Cinq lignes deviennent deux, une par équipe, et chaque agrégat ne voit que les lignes de son équipe.

Les règles à connaître

  • Chaque colonne sélectionnée doit figurer dans GROUP BY ou dans un agrégat. Sinon, il n’y a pas de valeur unique à afficher pour le groupe, et la requête échoue :
-- Input: products
-- name    | category
-- --------+---------
-- Blender | Kitchen
-- Toaster | Kitchen
-- Pillow  | Bedroom

SELECT name, category, COUNT(*) AS product_count
FROM products
GROUP BY category;

-- ERROR: column "products.name" must appear in the GROUP BY clause
--   or be used in an aggregate function
-- (SQLite runs it anyway and takes name from one row in each group)

Corrige-la en ajoutant la colonne au GROUP BY, ou en l’agrégeant elle aussi, avec MIN(name) par exemple.

  • Les NULL forment un seul groupe. Toutes les lignes avec un NULL dans la colonne de regroupement atterrissent dans le même groupe. Utilise COALESCE pour lui donner un libellé :
-- Input: products
-- name        | category
-- ------------+-----------
-- Notebook    | Stationery
-- Gift Card   | NULL
-- Pen Set     | Stationery
-- Mystery Box | NULL
-- Stapler     | Stationery

SELECT category, COUNT(*) AS product_count
FROM products
GROUP BY category;

-- Output:
-- category   | product_count
-- -----------+--------------
-- NULL       | 2
-- Stationery | 3

SELECT COALESCE(category, 'Uncategorized') AS category, COUNT(*) AS product_count
FROM products
GROUP BY category;

-- Output:
-- category      | product_count
-- --------------+--------------
-- Uncategorized | 2
-- Stationery    | 3
  • WHERE filtre les lignes avant le regroupement, HAVING filtre les groupes après. Seul HAVING peut tester un agrégat comme COUNT(*) > 2. Tout ce qui n’a pas besoin d’agrégat va dans WHERE, pour regrouper moins de lignes.
  • Les groupes reviennent dans un ordre quelconque. SQLite et SQL Server, par exemple, affichent Blue avant Red pour la requête des scores ci-dessus. Ajoute ORDER BY dès que l’ordre compte.

Syntaxe alternative

Tu peux regrouper par un alias de colonne, ou par la position de la colonne dans la liste du SELECT, au lieu de répéter une expression :

-- Input: orders
-- order_id | amount
-- ---------+-------
-- 1        | 35.00
-- 2        | 240.00
-- 3        | 18.50
-- 4        | 120.00
-- 5        | 64.00

SELECT CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END AS order_size,
       COUNT(*) AS order_count
FROM orders
GROUP BY order_size  -- or GROUP BY 1
ORDER BY order_size;
-- SQL Server allows neither: repeat the CASE expression in GROUP BY

-- Output:
-- order_size | order_count
-- -----------+------------
-- large      | 2
-- small      | 3

ROLLUP ajoute des sous-totaux et un total général. Les lignes de sous-total affichent NULL dans les colonnes qu’elles additionnent :

-- Input: sales
-- region | category | amount
-- -------+----------+-------
-- East   | Books    | 100.00
-- East   | Toys     | 50.00
-- West   | Books    | 80.00
-- East   | Books    | 40.00

SELECT region, category, SUM(amount) AS total_sales
FROM sales
GROUP BY ROLLUP(region, category);
-- MySQL: GROUP BY region, category WITH ROLLUP
-- SQLite has no ROLLUP

-- Output:
-- region | category | total_sales
-- -------+----------+------------
-- East   | Books    | 140.00
-- East   | Toys     | 50.00
-- East   | NULL     | 190.00
-- West   | Books    | 80.00
-- West   | NULL     | 80.00
-- NULL   | NULL     | 270.00

Un GROUP BY sans agrégat renvoie chaque valeur distincte une seule fois, comme SELECT DISTINCT category FROM products.

Quand utiliser GROUP BY ?

Utilise GROUP BY dès qu’une question dit « par » ou « pour chaque » : commandes par client, ventes par mois, employés par service. La plupart des usages entrent dans l’un de ces quatre cas.

Compter les lignes de chaque groupe

Combien de commandes par statut, combien de produits par catégorie, combien d’inscriptions par jour. COUNT(*) compte toutes les lignes du groupe, et COUNT(column) ne compte que les lignes où cette colonne n’est pas NULL.

Total, moyenne ou plage pour chaque groupe

SUM, AVG, MIN et MAX transforment les valeurs de chaque groupe en un seul nombre : chiffre d’affaires par client, panier moyen, produit le moins cher et le plus cher d’une catégorie. Une seule requête peut en renvoyer autant que tu veux.

Ventiler les résultats sur plusieurs colonnes

Liste plusieurs colonnes après GROUP BY pour obtenir une ligne par combinaison : ventes par région et par mois, stock par entrepôt et par type de produit. Seules les combinaisons présentes dans les données apparaissent.

Garder uniquement les groupes utiles

HAVING filtre les groupes une fois formés, à partir de leurs agrégats : services de plus de dix personnes, clients ayant dépensé plus de 1000 $, ou valeurs qui apparaissent plusieurs fois, ce qui permet de trouver les doublons.

Exemples concrets de GROUP BY

Compter les produits de chaque catégorie, même vide

GROUP BY ne crée des groupes que pour les valeurs existantes. Pour lister aussi les catégories sans produit, pars de la table des catégories et fais un LEFT JOIN sur les produits. Compte une colonne de la table jointe plutôt que * : une catégorie vide obtient quand même une ligne, remplie de NULL, et COUNT(*) la compte.

-- Input: categories
-- category_name
-- -------------
-- Audio
-- Cameras
-- Drones

-- Input: products
-- id | name       | category
-- ---+------------+---------
-- 1  | Earbuds    | Audio
-- 2  | Soundbar   | Audio
-- 3  | Action Cam | Cameras

-- Wrong: COUNT(*) counts the NULL row of an empty category
SELECT c.category_name, COUNT(*) AS product_count
FROM categories c
LEFT JOIN products p ON p.category = c.category_name
GROUP BY c.category_name
ORDER BY c.category_name;

-- Output:
-- category_name | product_count
-- --------------+--------------
-- Audio         | 2
-- Cameras       | 1
-- Drones        | 1

-- Right: COUNT(p.id) skips it
SELECT c.category_name, COUNT(p.id) AS product_count
FROM categories c
LEFT JOIN products p ON p.category = c.category_name
GROUP BY c.category_name
ORDER BY c.category_name;

-- Output:
-- category_name | product_count
-- --------------+--------------
-- Audio         | 2
-- Cameras       | 1
-- Drones        | 0

Trouver les trois catégories au plus gros chiffre d’affaires

Additionne les ventes de chaque catégorie, trie par total et garde les trois premières. Books arrive deuxième alors que chacune de ses ventes est inférieure à l’unique vente de Toys :

-- Input: purchases
-- category | amount
-- ---------+-------
-- Books    | 45.00
-- Toys     | 120.00
-- Garden   | 310.00
-- Books    | 80.00
-- Music    | 25.00

SELECT category, SUM(amount) AS revenue
FROM purchases
GROUP BY category
ORDER BY revenue DESC
LIMIT 3;
-- SQL Server has no LIMIT: write SELECT TOP 3 category, ... instead

-- Output:
-- category | revenue
-- ---------+--------
-- Garden   | 310.00
-- Books    | 125.00
-- Toys     | 120.00

Rapport des ventes par région et par mois

Regroupe par région et par mois extrait de la date, pour que chaque région ait une ligne par mois :

-- Input: sales
-- region | sale_date  | amount
-- -------+------------+-------
-- East   | 2024-01-08 | 120.00
-- West   | 2024-01-15 | 80.00
-- East   | 2024-01-22 | 95.00
-- East   | 2024-02-03 | 60.00
-- West   | 2024-02-11 | 150.00

SELECT region, EXTRACT(MONTH FROM sale_date) AS month, SUM(amount) AS total_sales
FROM sales
GROUP BY region, EXTRACT(MONTH FROM sale_date)
ORDER BY region, month;

-- Output:
-- region | month | total_sales
-- -------+-------+------------
-- East   | 1     | 215.00
-- East   | 2     | 60.00
-- West   | 1     | 80.00
-- West   | 2     | 150.00

SQL Server et SQLite n’ont pas EXTRACT. Utilise MONTH(sale_date) sous SQL Server et strftime('%m', sale_date) sous SQLite. Regroupe aussi par année dès que tes données couvrent plus d’une année.

Trouver les clients fidèles cette année

WHERE ne garde que les commandes de 2024, puis HAVING garde les clients qui en ont au moins deux. Le client 202 a deux commandes au total mais une seule en 2024, il est donc exclu :

-- Input: orders
-- order_id | customer_id | order_date
-- ---------+-------------+-----------
-- 1        | 201         | 2023-11-20
-- 2        | 202         | 2023-12-05
-- 3        | 201         | 2024-01-09
-- 4        | 202         | 2024-02-14
-- 5        | 201         | 2024-03-02

SELECT customer_id, COUNT(*) AS orders_2024
FROM orders
WHERE order_date >= '2024-01-01'
GROUP BY customer_id
HAVING COUNT(*) >= 2;

-- Output:
-- customer_id | orders_2024
-- ------------+------------
-- 201         | 2

Pour aller plus loin avec GROUP BY

Sur ce blog :

Documentation officielle :

Beekeeper Studio est une interface de base de données gratuite & open source

Le meilleur outil de requêtes & éditeur SQL que j’aie jamais utilisé. Il m’offre tout ce dont j’ai besoin pour gérer ma base de données. - ⭐⭐⭐⭐⭐ Mit

Beekeeper Studio est rapide, intuitif et facile à utiliser. Beekeeper prend en charge plein de bases de données et fonctionne parfaitement sous Windows, Mac et Linux.

La version Linux de Beekeeper est 100% complète : rien de bâclé, aucun compromis sur les fonctionnalités.

Ce que les utilisateurs disent de Beekeeper Studio

★★★★★
« Beekeeper Studio a complètement remplacé mon ancien workflow SQL. C’est rapide, intuitif, et ça rend le travail sur les bases de données agréable. »
— Alex K., développeur base de données
★★★★★
« J’ai essayé beaucoup d’interfaces de base de données, mais Beekeeper trouve l’équilibre parfait entre fonctionnalités et simplicité. Ça marche, tout simplement. »
— Sarah M., ingénieure full stack