COUNT(DISTINCT colonne) compte le nombre de valeurs différentes d’une colonne : une valeur qui apparaît dix fois compte une seule fois, et les NULL ne comptent pas du tout. Les exemples fonctionnent sous PostgreSQL, MySQL, SQLite et SQL Server.
Comment utiliser COUNT DISTINCT
Place DISTINCT dans COUNT(), devant la colonne ou l’expression à compter :
COUNT(DISTINCT expression)
Le plus simple, c’est de le comparer aux deux autres formes de COUNT. COUNT(*) compte les lignes, COUNT(column) compte les lignes où la colonne n’est pas NULL, et COUNT(DISTINCT column) compte les valeurs non NULL différentes :
-- Input: orders
-- order_id | customer_id
-- ---------+------------
-- 1 | 1042
-- 2 | 1077
-- 3 | 1042
-- 4 | NULL
SELECT COUNT(*) AS all_rows,
COUNT(customer_id) AS with_customer,
COUNT(DISTINCT customer_id) AS customers
FROM orders;
-- Output:
-- all_rows | with_customer | customers
-- ---------+---------------+----------
-- 4 | 3 | 2
Quatre commandes proviennent de deux clients : 1042 a commandé deux fois, et la commande 4 n’a aucun client.
Règles à connaître
- Les NULL ne sont pas comptés. Si une valeur manquante doit compter pour une de plus, ajoute-la toi-même :
-- Input: the orders table above
SELECT COUNT(DISTINCT customer_id)
+ MAX(CASE WHEN customer_id IS NULL THEN 1 ELSE 0 END) AS customers_and_guests
FROM orders;
-- Output: 3
-
MySQL et SQL Server ignorent la casse par défaut, donc ils comptent
'SQL'et'sql'comme une seule valeur. CompteLOWER(tag)quand la casse ne doit pas compter :
-- Input: tags
-- post_id | tag
-- --------+---------
-- 1 | SQL
-- 2 | sql
-- 3 | Postgres
SELECT COUNT(DISTINCT tag) FROM tags;
-- Output: 3 (2 in MySQL and SQL Server)
SELECT COUNT(DISTINCT LOWER(tag)) FROM tags;
-- Output: 2
-
DISTINCT fonctionne aussi dans
SUMetAVG, mais il supprime les valeurs répétées, pas les lignes répétées. Deux produits différents au même prix ne sont additionnés qu’une fois :
-- Input: order_lines
-- product | price
-- ---------+------
-- Pen | 2.00
-- Pencil | 2.00
-- Notebook | 5.00
SELECT SUM(price) AS total, SUM(DISTINCT price) AS distinct_total FROM order_lines;
-- Output:
-- total | distinct_total
-- ------+---------------
-- 9.00 | 7.00
Syntaxe alternative
COUNT(DISTINCT ...) prend une seule colonne. Pour compter les combinaisons différentes de plusieurs colonnes, compte les lignes d’une sous-requête DISTINCT. PostgreSQL et MySQL proposent aussi des raccourcis :
-- Input: orders
-- order_id | customer_id | product_id
-- ---------+-------------+-----------
-- 1 | 1 | 23
-- 2 | 12 | 3
-- 3 | 1 | 23
-- 4 | 12 | 5
SELECT COUNT(*) FROM (SELECT DISTINCT customer_id, product_id FROM orders) AS pairs;
-- Output: 3
-- PostgreSQL
SELECT COUNT(DISTINCT (customer_id, product_id)) FROM orders;
-- Output: 3
-- MySQL
SELECT COUNT(DISTINCT customer_id, product_id) FROM orders;
-- Output: 3
Tu verras aussi les colonnes collées en une seule chaîne avec CONCAT(). Il faut un séparateur : sans lui, le client 1 avec le produit 23 et le client 12 avec le produit 3 donnent tous les deux '123' :
-- Input: the orders table above
SELECT COUNT(DISTINCT CONCAT(customer_id, product_id)) FROM orders;
-- Output: 2
SELECT COUNT(DISTINCT CONCAT(customer_id, '_', product_id)) FROM orders;
-- Output: 3
Un comptage distinct exact doit trier ou hacher chaque valeur, ce qui devient lent sur les très grands tableaux. SQL Server propose APPROX_COUNT_DISTINCT(), plus rapide, qui reste à moins de 2 % du compte exact dans 97 % des cas :
-- SQL Server
-- Input: the orders table above
SELECT APPROX_COUNT_DISTINCT(customer_id) AS customers FROM orders;
-- Output: 2
Quand utiliser COUNT DISTINCT ?
Utilise COUNT DISTINCT quand la question est « combien de … différents ? » plutôt que « combien de lignes ? ». La plupart de ces questions entrent dans l’un de ces quatre cas.
Compter les visiteurs, clients ou produits uniques
Un journal de visites, de commandes ou de ventes enregistre encore et encore le même visiteur, client ou produit. COUNT DISTINCT sur son ID transforme ces lignes en décompte de têtes.
Compter les valeurs uniques par groupe
Ajoute GROUP BY et tu obtiens un comptage distinct par groupe : étudiants différents par cours, produits différents par vendeur, clients différents par mois.
Compter les combinaisons uniques de colonnes
Parfois, deux lignes ne sont « identiques » que si deux colonnes correspondent : le même utilisateur avec le même type de problème, ou la même route entre deux aéroports. Compte les combinaisons avec l’une des formes multi-colonnes de « Syntaxe alternative ».
Compter les valeurs uniques qui remplissent une condition
Place une expression CASE dans COUNT(DISTINCT ...) pour ne compter qu’une partie des lignes. Le CASE renvoie NULL pour les lignes que tu ne veux pas, et les NULL ne sont pas comptés : une seule requête peut donc renvoyer plusieurs comptages filtrés côte à côte.
Exemples concrets de COUNT DISTINCT
Utilisateurs actifs mensuels
Compte les utilisateurs qui ont fait quoi que ce soit en septembre, peu importe combien de fois ils sont revenus :
-- Input: events
-- event_id | user_id | event_date
-- ---------+---------+-----------
-- 1 | 301 | 2026-08-30
-- 2 | 302 | 2026-09-02
-- 3 | 302 | 2026-09-15
-- 4 | 305 | 2026-09-21
-- 5 | 302 | 2026-10-01
SELECT COUNT(DISTINCT user_id) AS active_users
FROM events
WHERE event_date >= '2026-09-01' AND event_date < '2026-10-01';
-- Output: 2
Produits vendus par chaque vendeur
COUNT(*) donne le nombre de ventes de chaque vendeur, et COUNT(DISTINCT product) le nombre de produits différents couverts par ces ventes :
-- Input: sales
-- vendor | product | color
-- -----------+----------+------
-- Acme | Mug | Red
-- Acme | Mug | Blue
-- Acme | Mug | Red
-- Acme | Tote Bag | Red
-- Brightside | Notebook | Black
SELECT vendor, COUNT(*) AS sales, COUNT(DISTINCT product) AS products
FROM sales
GROUP BY vendor;
-- Output:
-- vendor | sales | products
-- -----------+-------+---------
-- Acme | 4 | 2
-- Brightside | 1 | 1
Routes desservies par une compagnie aérienne
Une route, c’est une origine et une destination ensemble. Deux vols de LHR à JFK forment une seule route, mais JFK à LHR en est une autre :
-- Input: flights
-- flight_no | origin | destination
-- ----------+--------+------------
-- 101 | LHR | JFK
-- 105 | LHR | JFK
-- 102 | JFK | LHR
-- 301 | LHR | LAX
SELECT COUNT(*) AS routes
FROM (SELECT DISTINCT origin, destination FROM flights) AS r;
-- Output: 3
Clients selon le prix de leurs achats
Compte les clients qui ont acheté les produits 100 à 200, puis répartis-les selon le prix de leurs commandes. Le client 7 a passé deux commandes bon marché mais compte une fois, et le produit du client 15 est hors plage :
-- Input: orders
-- order_id | customer_id | product_id | price
-- ---------+-------------+------------+-------
-- 1 | 7 | 105 | 25.00
-- 2 | 7 | 142 | 40.00
-- 3 | 9 | 150 | 120.00
-- 4 | 12 | 188 | 310.00
-- 5 | 15 | 260 | 30.00
SELECT
COUNT(DISTINCT customer_id) AS customers,
COUNT(DISTINCT CASE WHEN price BETWEEN 1 AND 50 THEN customer_id END) AS low_spenders,
COUNT(DISTINCT CASE WHEN price BETWEEN 51 AND 150 THEN customer_id END) AS mid_spenders,
COUNT(DISTINCT CASE WHEN price > 150 THEN customer_id END) AS high_spenders
FROM orders
WHERE product_id BETWEEN 100 AND 200;
-- Output:
-- customers | low_spenders | mid_spenders | high_spenders
-- ----------+--------------+--------------+--------------
-- 3 | 1 | 1 | 1
Un client avec des commandes dans deux tranches de prix est compté dans les deux.
Pour aller plus loin avec COUNT DISTINCT
Sur ce blog :
-
Guide SQL GROUP BY :
COUNT,SUMetAVGpour chaque groupe - Guide pour trouver les doublons en SQL : trouve les valeurs qui apparaissent plus d’une fois
- Guide pour supprimer les doublons en SQL : supprime les copies en trop
- Guide de l’instruction SQL CASE : les conditions derrière les comptages conditionnels
-
Having vs Where en SQL : filtre sur un comptage avec
HAVING - Aide-mémoire SQL : les agrégats et le reste du SQL sur une seule page
Documentation officielle :
- PostgreSQL : expressions d’agrégat
- MySQL : COUNT(DISTINCT)
- SQLite : count()
- SQL Server : COUNT et APPROX_COUNT_DISTINCT
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.
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. »
« 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. »