L'estrazione di record unici in SQL è diventata un compito critico con il passaggio massiccio delle organizzazioni all'archiviazione di dati multidimensionali. A volte è necessario estrarre righe non ripetute in base a combinazioni di più colonne, altre volte — solo in base a una singola chiave.
Storia della questione:
Le prime versioni di SQL offrivano solo DISTINCT per filtrare i duplicati. In seguito sono apparse tecniche strutturali, tra cui GROUP BY per aggregazioni di set unici di valori e funzioni di finestra come ROW_NUMBER() per scenari più flessibili nella gestione dei duplicati, ad esempio: selezione dal "più recente" o "più vecchio" record.
Problema:
DISTINCT funziona solo a livello di set di campi in SELECT, mentre GROUP BY richiede aggregazioni. Le funzioni di finestra consentono logiche avanzate, ma il loro utilizzo provoca spesso errori se non si riflette sull'ordine di selezione delle righe. Spesso gli sviluppatori confondono questi approcci, gli errori portano a risultati errati.
Soluzione:
Esempio di codice:
Ottenere l'ultima registrazione degli ordini per ogni cliente:
WITH OrdersRank AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) as rn FROM Orders ) SELECT * FROM OrdersRank WHERE rn = 1;
Caratteristiche chiave:
È possibile utilizzare DISTINCT insieme a funzioni aggregate senza GROUP BY?
No, le funzioni aggregate richiedono raggruppamento, altrimenti si riceve un errore di sintassi.
SELECT COUNT(DISTINCT CustomerID) -- corretto SELECT SUM(Amount), DISTINCT CustomerID -- errore!
Cosa succede se in GROUP BY non si specificano tutti i campi non aggregati di SELECT?
Questo genererà un errore nella maggior parte dei DBMS: tutti i campi in SELECT, eccetto quelli aggregati, devono essere elencati in GROUP BY.
È possibile "rimuovere" i duplicati utilizzando funzioni di finestra senza una sottoselezione?
No: l'uso di ROW_NUMBER() all'interno di un singolo SELECT non filtra automaticamente i "ripetuti", è necessaria una query esterna per selezionare le righe desiderate.
Selezionati DISTINCT su tutte le colonne per una tabella di 20 milioni di righe: la query ha impiegato ore, risultato — timeout o crollo delle prestazioni del DB.
Vantaggi:
Svantaggi:
Utilizzate funzioni di finestra: ottenuta solo l'ultima registrazione necessaria per cliente in millisecondi; le precedenti e ripetute non sono state caricate.
Vantaggi:
Svantaggi: