COUNT(DISTINCT column) conta quanti valori diversi contiene una colonna: un valore che compare dieci volte conta una volta sola, e i NULL non vengono contati affatto. Gli esempi funzionano in PostgreSQL, MySQL, SQLite e SQL Server.
Come usare COUNT DISTINCT
Metti DISTINCT dentro COUNT(), davanti alla colonna o all'espressione da contare:
COUNT(DISTINCT expression)
Si capisce meglio confrontandolo con le altre due forme di COUNT. COUNT(*) conta le righe, COUNT(column) conta le righe in cui la colonna non è NULL, e COUNT(DISTINCT column) conta i diversi valori non NULL:
-- 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
Quattro ordini sono arrivati da due clienti: 1042 ha ordinato due volte, e l'ordine 4 non ha nessun cliente.
Regole da sapere
- I NULL non vengono contati. Se un valore mancante deve valere come uno in più, aggiungilo tu:
-- 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 e SQL Server ignorano maiuscole e minuscole per impostazione predefinita, quindi contano
'SQL'e'sql'come un unico valore. ContaLOWER(tag)quando le maiuscole non devono contare:
-- 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 funziona anche dentro
SUMeAVG, ma elimina i valori ripetuti, non le righe ripetute. Due prodotti diversi con lo stesso prezzo vengono sommati una volta sola:
-- 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
Sintassi alternative
COUNT(DISTINCT ...) accetta una sola colonna. Per contare le diverse combinazioni di più colonne, conta le righe di una subquery DISTINCT. PostgreSQL e MySQL hanno anche delle scorciatoie:
-- 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
Vedrai anche le colonne unite in un'unica stringa con CONCAT(). Serve un separatore: senza, il cliente 1 con il prodotto 23 e il cliente 12 con il prodotto 3 diventano entrambi '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 conteggio distinto esatto deve ordinare o calcolare l'hash di ogni valore, e su tabelle molto grandi diventa lento. SQL Server ha APPROX_COUNT_DISTINCT(), che è più veloce e resta entro il 2% del conteggio esatto nel 97% dei casi:
-- SQL Server
-- Input: the orders table above
SELECT APPROX_COUNT_DISTINCT(customer_id) AS customers FROM orders;
-- Output: 2
Quando usare COUNT DISTINCT?
Usa COUNT DISTINCT quando la domanda è “quanti … diversi?” e non “quante righe?”. La maggior parte di queste domande rientra in uno di questi quattro casi.
Contare visitatori, clienti o prodotti unici
Un log di visite, ordini o vendite registra lo stesso visitatore, cliente o prodotto più e più volte. COUNT DISTINCT sul suo ID trasforma quelle righe in un conteggio delle persone o degli articoli.
Contare i valori unici in ogni gruppo
Aggiungi GROUP BY e ottieni un conteggio distinto per gruppo: studenti diversi per corso, prodotti diversi per venditore, clienti diversi per mese.
Contare le combinazioni uniche di colonne
A volte due righe sono “uguali” solo quando coincidono due colonne: lo stesso utente con lo stesso tipo di problema, o la stessa rotta tra due aeroporti. Conta le combinazioni con una delle forme multi-colonna viste in “Sintassi alternative”.
Contare i valori unici che soddisfano una condizione
Metti un'espressione CASE dentro COUNT(DISTINCT ...) per contare solo alcune righe. Il CASE restituisce NULL per le righe che non ti interessano, e i NULL non vengono contati, quindi una sola query può restituire più conteggi filtrati uno accanto all'altro.
Esempi reali di COUNT DISTINCT
Utenti attivi mensili
Conta gli utenti che hanno fatto qualcosa a settembre, indipendentemente da quante volte sono tornati:
-- 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
Prodotti venduti da ogni venditore
COUNT(*) restituisce il numero di vendite di ogni venditore, e COUNT(DISTINCT product) quanti prodotti diversi coprono quelle vendite:
-- 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
Le rotte di una compagnia aerea
Una rotta è l'insieme di origine e destinazione. Due voli da LHR a JFK sono una sola rotta, ma JFK-LHR è un'altra:
-- 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
Clienti per prezzo degli acquisti
Conta i clienti che hanno acquistato i prodotti da 100 a 200, poi suddividili in base al prezzo dei loro ordini. Il cliente 7 ha fatto due ordini economici ma conta una volta sola, e il prodotto del cliente 15 è fuori intervallo:
-- 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 cliente con ordini in due fasce di prezzo viene contato in entrambe.
Approfondimenti su COUNT DISTINCT
Su questo blog:
-
Guida a SQL GROUP BY:
COUNT,SUMeAVGper ogni gruppo - Guida per trovare i duplicati in SQL: trova i valori che compaiono più di una volta
- Guida per rimuovere i duplicati in SQL: elimina le copie in eccesso
- Guida all'istruzione SQL CASE: le condizioni dietro i conteggi condizionali
-
Having vs Where in SQL: filtra su un conteggio con
HAVING - Cheat sheet SQL: aggregazioni e il resto di SQL in una pagina
Documentazione ufficiale:
- PostgreSQL: espressioni di aggregazione
- MySQL: COUNT(DISTINCT)
- SQLite: count()
- SQL Server: COUNT e APPROX_COUNT_DISTINCT
Beekeeper Studio è una GUI per database gratuita & open source
Il miglior strumento per query & editor SQL che abbia mai usato. Offre tutto ciò che mi serve per gestire il mio database. - ⭐⭐⭐⭐⭐ Mit
Beekeeper Studio è veloce, intuitivo e facile da usare. Beekeeper supporta tantissimi database e funziona alla grande su Windows, Mac e Linux.
Cosa dicono gli utenti di Beekeeper Studio
"Beekeeper Studio ha sostituito completamente il mio vecchio flusso di lavoro SQL. È veloce, intuitivo e rende di nuovo piacevole lavorare con i database."
"Ho provato molte GUI per database, ma Beekeeper trova l'equilibrio perfetto tra funzionalità e semplicità. Funziona e basta."