Torna all'elenco degli articoli Articoli
Tempo di lettura: 9 minuti

Che differenza c'è tra COUNT(*), COUNT(1), COUNT(nome colonna) e COUNT(DISTINCT nome colonna)?

Avete notato che esistono diverse varianti della funzione SQL COUNT()? Questo articolo spiega i vari argomenti e il loro utilizzo.

Se usate SQL, probabilmente conoscete bene la funzione COUNT(). Anche se è relativamente semplice, può essere utilizzata in diversi modi, ognuno con una funzione specifica. Immagino che abbiate incontrato righe di codice che contenevano la funzione COUNT(*) o COUNT(1). Probabilmente avete visto anche altri usi della funzione COUNT(), come COUNT(nome colonna) e COUNT(DISTINCT nome colonna), anche se non li avete usati.

Probabilmente vi state chiedendo cosa fa ogni variante di COUNT(). Scopriamolo!

Il modo migliore per esercitarsi con SQL è il nostro corso interattivo Esercizi di Pratica su SQL. Contiene oltre 90 esercizi pratici di SQL per ripassare e rinfrescare gli argomenti SQL più importanti, tra cui COUNT() e GROUP BY. Ogni volta che risolverete un esercizio, acquisirete fiducia nelle vostre capacità in SQL.

Cosa fa la funzione COUNT()?

Come potete immaginare, la funzione COUNT() conta. Ma cosa conta? La funzione COUNT() fa parte delle funzioni aggregate di SQL. Conta il numero di righe che soddisfano i criteri definiti tra le parentesi. Non restituisce le righe in sé, ma mostra il numero di righe che soddisfano i criteri.

A proposito di funzioni aggregate, esse sono estremamente utili nei rapporti SQL. Se volete soddisfare la vostra curiosità, nel nostro corso Creare semplici rapporti SQL troverete molte informazioni sulle funzioni aggregate e sul "raggruppamento per".

Torniamo ora al conteggio. Naturalmente, si possono contare molte cose diverse. Ecco perché esistono più varianti della funzione COUNT(). In questo articolo mi concentrerò su quattro di esse:

  • COUNT(*)
  • COUNT(1)
  • COUNT(colonna nome)
  • COUNT(DISTINCT colonna nome)

COUNT(*) vs COUNT(1)

Potreste aver visto diverse discussioni sulle differenze tra COUNT(*) e COUNT(1). E forse il tentativo di trovare la risposta vi ha confuso ancora di più. Quindi, c'è qualche differenza? La risposta semplice è no: non c'è alcuna differenza.

La funzione COUNT(*) conta il totale delle righe della tabella, compresi i valori di NULL. La semantica di COUNT(1) è leggermente diversa; ne parleremo più avanti. Tuttavia, i risultati per COUNT(*) e COUNT(1) sono identici.

Verifichiamo questa affermazione con un esempio di query. Supponiamo di avere una tabella chiamata ordini che contiene queste colonne:

  • id_ordine: l'id dell'ordine.
  • id_cliente: l'id del cliente che ha effettuato l'ordine.
  • valore_ordine: il valore totale degli articoli ordinati, in euro.
  • data_di_pagamento: quando l'ordine è stato pagato dal cliente.

Se volessi contare il numero di righe dell'intera tabella, utilizzerei la funzione COUNT() nel modo seguente:

SELECT COUNT(*) AS numero_di_righe
FROM ordini;

Come si vede, ho usato la funzione COUNT(*). Il risultato apparirà nella nuova colonna numero_di_righe:

numero_di_righe
8

Ok, ma se invece usassi COUNT(1)? Ecco qui:

SELECT COUNT(1) AS numero_di_righe
FROM ordini;

Il codice è essenzialmente lo stesso. L'unica differenza è che ho usato COUNT(1) invece di COUNT(*). E il risultato? Restituisce lo stesso numero di righe:

numero_di_righe
8

È diffusa l'idea errata che "1" in COUNT(1) significhi "conta i valori nella prima colonna e restituisci il numero di righe". Da questo equivoco ne segue un altro: COUNT(1) è più veloce perché conta solo la prima colonna, mentre COUNT(*) utilizza l'intera tabella per ottenere lo stesso risultato.

Questo non è vero. Il numero nella parentesi non indica il numero della colonna nella tabella. Se mettete un numero qualsiasi tra le parentesi, vi garantisco che il risultato sarà lo stesso. Volete una prova? Eccola qui:

SELECT COUNT(-13) AS numero_di_righe
FROM ordini;

Se la prima affermazione fosse vera, il codice qui sopra significherebbe che voglio contare il numero di righe nella tredicesima colonna. Ci sono solo quattro colonne nella tabella ordini, quindi non esiste una tredicesima colonna. Di sicuro non troveremo la colonna -13, qualunque cosa significhi. Volete vedere il risultato del codice? Non siate sorpresi:

numero_di_righe
8

Ancora una volta, il risultato è lo stesso. Che cosa significa il valore nella parentesi di COUNT()? È il valore che la funzione COUNT() assegnerà a ogni riga della tabella. La funzione conterà quindi quante volte sarà stato assegnato l'asterisco (*) o (1) o (-13). Naturalmente, verrà assegnato un numero di volte pari al numero di righe della tabella. In altre parole, COUNT(1) assegna il valore della parentesi (il numero 1, in questo caso) a ogni riga della tabella, poi la stessa funzione conta quante volte è stato assegnato il valore nella parentesi (1, nel nostro caso); naturalmente, questo sarà sempre uguale al numero di righe della tabella. Le parentesi possono contenere qualsiasi valore; l'istruzione non funzionerà solamente se lascerete le parentesi vuote.

Proviamo a fare una sciocchezza. Invece di un numero, mettiamo tra le parentesi il seguente valore: "saranno sempre 8 righe". Ecco il codice:

SELECT COUNT('saranno sempre 8 righe') AS numero_di_righe
FROM ordini;

Eseguite il codice e - sorpresa, sorpresa - il risultato è davvero otto righe:

numero_di_righe
8

Poiché non importa quale valore si inserisce nella parentesi, ne consegue che COUNT(*) e COUNT(1) sono esattamente la stessa cosa. Sono perfettamente equivalenti, perché il valore tra le parentesi di COUNT() serve solo a dire alla query che cosa conterà.

Se queste affermazioni sono esattamente uguali, non c'è alcuna differenza tra le prestazioni. Non lasciate che l'asterisco (*) vi faccia pensare che abbia lo stesso utilizzo dell'istruzione SELECT *. No, COUNT(*) non esaminerà l'intera tabella prima di restituire il numero di righe, diventando più lento di COUNT(1).

Quindi, alla fine, chi vince in questa drammatica battaglia tra COUNT(*) e COUNT(1)? Nessuno: è un pareggio; sono esattamente uguali. Tuttavia, consiglio di usare COUNT(*), perché è molto più comune. Genera anche meno confusioni, in quanto porta gli altri utenti di SQL a capire che la funzione conterà tutti i numeri della tabella, compresi i valori NULL.

COUNT(*) vs COUNT(nome colonna)

Che ne dite di questo, COUNT(*) vs COUNT(nome colonna). C'è qualche differenza? Certo che sì!

Come avete già imparato, COUNT(*) conterà tutte le righe della tabella, compresi i valori di NULL. D'altra parte, COUNT(nome colonna) conterà tutte le righe della colonna specificata, escludendo i valori NULL.

Come già sapete, ci sono otto righe nella tabella ordini. Vediamo quante righe saranno contate quando userò la colonna id_ordine per il conteggio (immaginando di voler vedere quanti ordini sono stati effettuati). Avremo di nuovo otto righe, giusto? Vediamo:

SELECT COUNT(id_ordine) AS numero_di_ordini
FROM ordini;

Otteniamo lo stesso risultato? No, ci sono sette ordini, non otto.

numero_di_ordini
7

È un errore? No, non lo è; in realtà ci sono solo sette ordini con un id_ordine; una riga ha un valore NULL invece di un id_ordine corretto. Di seguito è riportata la riga che fa emergere la differenza:

id_ordineid_clienteprezzo_ordinedata_ordine
NULLCU0921327,85NULL

Ricordate sempre: COUNT(nome colonna) conterà solo le righe in cui la colonna data NON è NULL.

Ora passiamo a un esempio interessante e combiniamo entrambe le varianti di COUNT() in un'unica query. Supponiamo di voler visualizzare l'id del cliente con il numero totale di ordini che ha eseguito. Voglio anche visualizzare il numero totale di ordini pagati da quel cliente (gli ordini pagati non hanno un valore NULL nella colonna data_di_pagamento). Ecco come fare:

SELECT	id_cliente,
		COUNT(*) AS numero_di_ordini,
		COUNT(data_di_pagamento) AS numero_di_ordini_pagati
FROM ordini
GROUP BY id_cliente;

La query calcolerà innanzitutto il numero totale di ordini utilizzando COUNT(*), vale a dire includerà i valori NULL. Poi la parte COUNT (data_di_pagamento) AS numero_di_ordini_pagati conterà le righe della colonna data_di_pagamento che sono NOT NULL. Voglio i risultati per ogni cliente, quindi ho raggruppato i risultati in base alla colonna id_cliente. Ecco cosa ottengo:

id_clientenumero_di_ordininumero_di_ordini_pagati
CU01211
CU04911
CU05222
CU09210
CU10822
CU14911

Si può notare che la differenza si verifica per il cliente CU092.

I principi della combinazione di GROUP BY e COUNT() sono illustrati in questo articolo sulle funzioni GROUP BY e aggregate in SQL. Se volete fare un po' di pratica, ecco cinque esempi di GROUP BY.

COUNT() permette di utilizzare come argomento sia espressioni che nomi di colonne. Sapete come trovare il numero di ordini superiori a 1.000 euro utilizzando solo la funzione COUNT()? Ecco come fare:

SELECT COUNT(CASE WHEN prezzo_ordine > 1000 THEN 1 END) 
AS ordini_significativi
FROM ordini;

Invece di inserire le condizioni alla fine della query e di filtrare dopo che la funzione COUNT() ha compiuto il proprio lavoro, possiamo utilizzare l'istruzione CASE. È quello che ho fatto nella query qui sopra. Si usa come un'istruzione IF-THEN-ELSE. CASE è seguita dalla condizione, definita dalle istruzioni WHEN e THEN. Può essere inserita anche un'istruzione ELSE, ma in questo caso non è necessaria: mi interessa solo contare il numero di valori, non i valori stessi. Ogni istruzione CASE termina con l'istruzione END.

L'istruzione COUNT() precedente ha la seguente funzione:

  1. Trova tutti i valori della colonna prezzo_ordine superiori a 1.000.
  2. Assegna il valore 1 (si può assegnare qualsiasi valore) a questi valori.
  3. Assegna NULL alle righe con prezzi inferiori a 1.000.
  4. Conta il numero di 1 assegnati.
  5. Mostra il risultato nella colonna ordini_significativi.

Ecco il risultato:

ordini_significativi
5

COUNT(nome_colonna) vs COUNT (DISTINCT nome_colonna)

Potete probabilmente immaginare quale sia la differenza tra le due versioni della funzione COUNT(). COUNT(nome_colonna) includerà i valori duplicati nel conteggio. Al contrario, COUNT (DISTINCT nome_colonna) conterà solo le righe distinte (uniche) nella colonna definita.

Se si vuole contare il numero di clienti che hanno effettuato un ordine, forse COUNT (nome_colonna) funzionerà. Proviamo questo semplice codice:

SELECT COUNT (id_cliente) AS numero_di_clienti
FROM ordini;

Lo conoscete già; ho già usato la funzione COUNT(nome colonna). Questa volta conta tutte le righe della colonna id_cliente e il risultato viene mostrato nella colonna numero_di_clienti. Ecco il risultato:

numero_di_clienti
8

Controlliamo il risultato osservando l'intera tabella ordini:

id_ordineid_clienteprezzo_ordinedata_ordine
OR2020-01CU108154872020-01-08
OR2020-28CU149154872020-01-14
OR2020-12CU10812549,222020-01-09
OR2020-91CU012542,55NULL
NULLCU0921327,85NULL
OR2020-112CU049150002020-02-28
OR2020-213CU0521502020-03-12
OR2020-213CU0522002020-03-12

Ci sono otto righe, ma è davvero questo il numero dei clienti? Si noti che i clienti CU108 e CU052 compaiono due volte. Se voglio il numero reale di clienti, devo contare ogni cliente una sola volta. Come posso fare? Utilizzando COUNT(DISTINCT id_cliente):

SELECT COUNT(DISTINCT id_cliente) AS numero_di_clienti
FROM ordini;

Anche questa query conterà le righe della colonna id_cliente, ma conterà ogni cliente solo una volta. Ciò è dovuto alla parola chiave DISTINCT. Osservate il risultato:

numero_di_clienti
6

Questo è il risultato corretto; in realtà ci sono solo sei clienti unici.

Pensate di poter contare su COUNT()?

Ora che conoscete diverse varianti comuni della funzione COUNT(), potete creare calcoli e report più complessi. COUNT() è una delle funzioni aggregate più utilizzate, quindi è fondamentale che comprendiate chiaramente le diverse varianti di COUNT() e i loro scopi. Se alcune delle varianti della funzione COUNT() discusse in questo articolo non sono state chiare, fatemelo sapere nella sezione dei commenti. Sarò lieto di aiutarvi. E per fare più pratica con COUNT(), provate il nostro corso Creare semplici rapporti SQL .