DISTINCT rimuove le righe duplicate
Di default, SELECT restituisce ogni riga che corrisponde, duplicati compresi. DISTINCT dice a SQLite di unire le righe identiche nelle colonne che hai selezionato, così ogni combinazione unica compare una sola volta.
Entrano cinque righe, ne escono tre. SQLite ha guardato la colonna customer, ha scartato le ripetizioni e ha restituito una riga per ogni valore unico. L'ordine non è garantito: aggiungi ORDER BY se ti interessa.
DISTINCT si applica all'intero elenco della select
Questo confonde molte persone. DISTINCT non sceglie una colonna da deduplicare: deduplica righe intere in base a tutte le colonne che hai selezionato.
Ogni coppia unica (customer, country) compare una volta. Se lo stesso cliente comparisse con due paesi diversi, vedresti entrambe le righe: per SQLite non sono duplicati.
Non esiste una sintassi DISTINCT(customer) che ignori le altre colonne. Le parentesi sono allettanti, ma SELECT DISTINCT(customer), country viene interpretato esattamente come SELECT DISTINCT customer, country: le parentesi raggruppano solo un'espressione. Se vuoi davvero una riga per cliente con un paese scelto, è un lavoro per GROUP BY più un'aggregazione.
COUNT(DISTINCT col)
Un'esigenza comune: quanti valori unici ci sono in una colonna? COUNT(*) conta le righe, COUNT(col) conta i valori non NULL e COUNT(DISTINCT col) conta i valori unici non NULL.
Cinque ordini, tre clienti unici, tre paesi unici. COUNT(DISTINCT ...) è la forma aggregata più utile di DISTINCT: la userai ogni volta che vuoi contare "quante cose diverse sono comparse".
Nota che SQLite ammette una sola colonna dentro COUNT(DISTINCT ...). Per contare le combinazioni uniche di più colonne, racchiudile in una subquery: SELECT COUNT(*) FROM (SELECT DISTINCT a, b FROM t).
Come DISTINCT tratta NULL
NULL ha una reputazione strana in SQL perché NULL = NULL dà NULL, non TRUE. Ma DISTINCT fa un'eccezione speciale: ai fini della deduplicazione, tutti i NULL sono considerati uguali tra loro.
Tornano tre righe: 'ada@example.com', 'dan@example.com' e un solo NULL. Le tre email NULL si sono unite in una. La stessa regola vale per GROUP BY e per le operazioni sugli insiemi come UNION: utile da ricordare quando ti chiedi "perché quella riga NULL compare una volta invece di tre?"
DISTINCT viene eseguito prima di ORDER BY e LIMIT
Le clausole di una SELECT seguono un ordine logico: FROM → WHERE → GROUP BY → HAVING → SELECT/DISTINCT → ORDER BY → LIMIT. Quindi DISTINCT filtra prima i duplicati, poi ORDER BY ordina ciò che resta, poi LIMIT lo taglia.
WHERE tiene quattro righe, DISTINCT unisce i duplicati di Boris, ORDER BY ordina alfabeticamente, LIMIT restituisce le prime due. Vale la pena seguirlo passo per passo almeno una volta: la confusione sull'ordine dei risultati nasce di solito dal dimenticare quale passaggio avviene quando.
DISTINCT contro GROUP BY
Per la pura deduplicazione, queste due query restituiscono le stesse righe:
Stesso risultato. La differenza sta in cosa puoi fare dopo:
DISTINCTserve per "dammi le righe uniche" e nient'altro.GROUP BYserve per "dividi le righe in gruppi e calcola qualcosa per ogni gruppo":COUNT(*),SUM(amount),MAX(created_at)e così via.
Se ti ritrovi a usare DISTINCT e poi ti accorgi che vuoi anche un totale per cliente, è il segnale per passare a GROUP BY:
Una riga per cliente, con le aggregazioni che volevi. DISTINCT non poteva farlo: non ha modo di esprimere "una riga per gruppo più una somma".
Alcune cose a cui fare attenzione
- Prestazioni.
DISTINCTdi solito richiede a SQLite di ordinare o calcolare un hash delle righe per trovare i duplicati. Su risultati grandi, un indice sulle colonne deduplicate aiuta. Se faiSELECT DISTINCTsu tutte le colonne di una tabella larga, chiediti se ti servono davvero tutte. DISTINCT *è raro. È legale,SELECT DISTINCT * FROM tdeduplica righe intere, ma se la tabella ha una chiave primaria ogni riga è già unica, quindi non serve a nulla.- Non confonderlo con
UNIQUE.UNIQUEè un vincolo su una tabella che impedisce fin dall'inizio l'inserimento di valori duplicati.DISTINCTè un filtro applicato durante la query che nasconde i duplicati nel risultato. Strumenti diversi, lavori diversi.
Prossimo passo: le espressioni CASE
Una volta che sai dare forma alle righe del risultato con SELECT, WHERE, ORDER BY e DISTINCT, il passo successivo è la logica condizionale dentro una query. Le espressioni CASE ti permettono di restituire valori diversi in base a delle condizioni: l'equivalente SQL di una catena di if/else, e la prossima pagina le spiega.
Domande frequenti
Come funziona SELECT DISTINCT in SQLite?
SELECT DISTINCT rimuove le righe duplicate dal risultato. SQLite confronta ogni colonna dell'elenco della select e tiene una riga per ogni combinazione unica. Viene applicato dopo WHERE e JOIN, ma prima di ORDER BY e LIMIT.
Posso usare DISTINCT su più colonne in SQLite?
Sì: DISTINCT si applica sempre all'intero elenco della select, non a una singola colonna. SELECT DISTINCT city, country FROM users restituisce ogni coppia unica (city, country). Non esiste una sintassi DISTINCT(city) che ignori le altre colonne; se ti serve, usa GROUP BY con un'aggregazione.
Come gestisce DISTINCT i valori NULL in SQLite?
Ai fini della deduplicazione, DISTINCT considera NULL uguale agli altri NULL: quindi più righe con NULL si riducono a una. È diverso da come funziona = nelle clausole WHERE, dove NULL = NULL è sconosciuto. È una regola speciale solo per DISTINCT, GROUP BY e UNION.
Che differenza c'è tra DISTINCT e GROUP BY in SQLite?
Per la sola deduplicazione, SELECT DISTINCT col e SELECT col FROM t GROUP BY col producono risultati identici. La differenza è nell'intenzione: usa DISTINCT quando vuoi solo righe uniche, e GROUP BY quando vuoi anche calcolare aggregazioni come COUNT(*) o SUM(amount) per ogni gruppo.