22nd May 2023 Tempo di lettura: 9 minuti Come utilizzare il metodo SQL RANK OVER (PARTITION BY) Tihomir Babic sql rank Indice Che cos'è RANK()? Cosa fa RANK()? Come funziona RANK() con OVER (ORDER BY) Come funziona RANK() con OVER (PARTITION BY) Esempio bonus Aggiungere RANK() al vocabolario SQL Classificare i dati in SQL è un gioco da ragazzi se si sa come usare RANK() per classificare su una partizione. Questo articolo mostra come farlo e come RANK() si differenzia da DENSE_RANK() e ROW_NUMBER(). Se lavorate con SQL in ambito professionale, vi sarà capitato almeno una volta di dover classificare dei dati. Pensate alla classifica dei mesi/anni/trimestri in base alle entrate o ai costi, ai prodotti più venduti, ai post più visti o alle canzoni ascoltate in streaming, ai dipendenti in base allo stipendio, alle filiali più redditizie, e così via. O alla classifica dei libri in base alle loro vendite. Il fatto è che spesso è necessario classificare i dati all'interno di una determinata categoria, o partizione, come la chiamiamo noi. L'SQL RANK OVER (PARTITION BY) entra in gioco! Questo è un tipico esempio di funzioni finestra in SQL. Per una spiegazione più dettagliata delle funzioni finestra, il nostro corso sulle funzioni finestra è il migliore. Attraverso 218 esercizi interattivi, imparerete a conoscere meglio PARTITION BY e altre clausole di funzioni finestra, come ORDER BY, ROWS e RANGE. Queste funzioni sono utilizzate non solo nelle classifiche, ma anche nelle funzioni di aggregazione e di analisi. Torniamo alle vendite di libri. Guardate questa tabella, con il codice per crearla qui. Come classifichiamo le vendite di libri in ciascuna lingua? idtitleauthororiginal_languagesalesclassify_under 1The HobbitJ. R. R. TolkienEnglish100Fantasy 2Watership DownRichard AdamsEnglish50Fantasy 3Harry Potter and the Philosopher's StoneJ. K. RowlingEnglish120Fantasy 4The PlagueAlbert CamusFrench12Classics 5The Divine ComedyDante AlighieriItalian12Poetry 6War and PeaceLeo TolstoyRussian36Classics 7Nineteen Eighty-FourGeorge OrwellEnglish30Classics 8Andromeda NebulaIvan YefremovRussian20Science fiction 9The Little PrinceAntoine de Saint-ExupéryFrench200Kids 10The StrangerAlbert CamusFrench10Classics 11The Adventures of PinocchioCarlo CollodiItalian35Kids 12The Name of the RoseUmberto EcoItalian50Classics 13One Hundred Years of SolitudeGabriel García MárquezSpanish50Classics 14Don QuixoteMiguel de CervantesSpanish500Classics 15LolitaVladimir NabokovEnglish50Classics La soluzione è semplice se si sa che la lingua, in questo esempio, agisce come una sorta di partizione dei dati. SELECT original_language, title, author, sales, RANK() OVER (PARTITION BY original_language ORDER BY sales DESC) AS sales_rank FROM books; Ed eccola qui! original_languagetitleauthorsalessales_rank EnglishHarry Potter and the Philosopher's StoneJ. K. Rowling1201 EnglishThe HobbitJ. R. R. Tolkien1002 EnglishLolitaVladimir Nabokov503 EnglishWatership DownRichard Adams503 EnglishNineteen Eighty-FourGeorge Orwell305 FrenchThe Little PrinceAntoine de Saint-Exupéry2001 FrenchThe PlagueAlbert Camus122 FrenchThe StrangerAlbert Camus103 ItalianThe Name of the RoseUmberto Eco501 ItalianThe Adventures of PinocchioCarlo Collodi352 ItalianThe Divine ComedyDante Alighieri123 RussianWar and PeaceLeo Tolstoy361 RussianAndromeda NebulaIvan Yefremov202 SpanishDon QuixoteMiguel de Cervantes5001 SpanishOne Hundred Years of SolitudeGabriel García Márquez502 Ora analizziamo questo esempio. Che cos'è RANK()? In termini più semplici, RANK() è una funzione finestra. Le funzioni finestra di SQL sono simili alle funzioni aggregate in quanto vengono applicate a un gruppo di righe. Una grande differenza: le funzioni finestra mantengono i dettagli delle singole righe, a differenza delle funzioni aggregate con GROUP BY. Cosa fa RANK()? Come suggerisce il nome, classifica i dati. Questo la rende una funzione finestra di classificazione, insieme a DENSE_RANK() e ROW_NUMBER(). Quando si usa una di queste funzioni finestra, deve essere accompagnata dalla clausola OVER (ORDER BY). La clausola OVER() è obbligatoria per qualsiasi funzione finestra. È quella che trasforma una funzione "normale" in una funzione finestra. Per queste funzioni di classificazione, ORDER BY tra parentesi definisce l'ordine in cui viene eseguita la classificazione. L'ordine può essere ascendente o discendente. Si tenga presente che non influisce sull'ordine delle righe nel risultato; questo viene fatto con un ORDER BY alla fine della query. Per saperne di più, consultare il nostro articolo sulla funzione RANK(). Come funziona RANK() con OVER (ORDER BY) Utilizziamo il set di dati di cui sopra. Prendiamo l'intera tabella e classifichiamo i libri in base alle vendite. Vediamo cosa succede. SELECT title, author, sales, RANK() OVER (ORDER BY sales DESC) AS sales_rank FROM books; Questa è la stessa query della precedente, solo che questa non seleziona la lingua e non usa PARTITION BY. Quindi, la funzione RANK() è seguita da OVER(). La clausola ORDER BY indica alla funzione di classificare i dati in base alle vendite in ordine decrescente, cioè dai libri più venduti a quelli meno venduti. Poiché la clausola PARTITION BY è omessa, la funzione classifica l'intera tabella. Ecco le prime dieci righe dell'output. titleauthorsalessales_rank Don QuixoteMiguel de Cervantes5001 The Little PrinceAntoine de Saint-Exupéry2002 Harry Potter and the Philosopher's StoneJ. K. Rowling1203 The HobbitJ. R. R. Tolkien1004 LolitaVladimir Nabokov505 Watership DownRichard Adams505 The Name of the RoseUmberto Eco505 One Hundred Years of SolitudeGabriel García Márquez505 War and PeaceLeo Tolstoy369 The Adventures of PinocchioCarlo Collodi3510 L'aspetto critico da notare è che ci sono quattro libri con 50 milioni di copie vendute, tutti classificati al quinto posto. Questo è il modo in cui RANK() si differenzia dalle altre due funzioni di classificazione a finestra: assegna lo stesso rango a valori uguali. Quando la funzione raggiunge il valore di vendita successivo (in questo caso, 36 milioni di copie vendute), non assegna il valore di rango successivo (6), ma salta per aggiustare il conteggio dei valori di vendita legati. Come già detto, il grado "5" compare quattro volte; pertanto, il grado successivo assegnato è il nove. DENSE_RANK() Anche classifica i legami con la stessa posizione. Tuttavia, a differenza di RANK(), non salta i valori di rango basati sui legami. Gli stessi dati classificati con DENSE_RANK() sono i seguenti. titleauthorsalessales_rank Don QuixoteMiguel de Cervantes5001 The Little PrinceAntoine de Saint-Exupéry2002 Harry Potter and the Philosopher's StoneJ. K. Rowling1203 The HobbitJ. R. R. Tolkien1004 LolitaVladimir Nabokov505 Watership DownRichard Adams505 The Name of the RoseUmberto Eco505 One Hundred Years of SolitudeGabriel García Márquez505 War and PeaceLeo Tolstoy366 The Adventures of PinocchioCarlo Collodi357 Dopo diversi libri classificati al quinto posto, la posizione successiva è la sesta, non la nona come in RANK(). Che dire di ROW_NUMBER()? Non si preoccupa dei legami o dei salti. Si limita a classificare le righe in modo sequenziale. Di seguito sono riportate le prime dieci righe ottenute con ROW_NUMBER(). titleauthorsalessales_rank Don QuixoteMiguel de Cervantes5001 The Little PrinceAntoine de Saint-Exupéry2002 Harry Potter and the Philosopher's StoneJ. K. Rowling1203 The HobbitJ. R. R. Tolkien1004 LolitaVladimir Nabokov505 Watership DownRichard Adams506 The Name of the RoseUmberto Eco507 One Hundred Years of SolitudeGabriel García Márquez508 War and PeaceLeo Tolstoy369 The Adventures of PinocchioCarlo Collodi3510 Le differenze tra queste funzioni sono spiegate nella panoramica delle funzioni di classificazione. Come funziona RANK() con OVER (PARTITION BY) La clausola PARTITION BY divide i dati in partizioni o sottoinsiemi. Se utilizzata con RANK(), significa che i dati vengono classificati all'interno della partizione. Quando si raggiunge la seconda partizione, la classifica viene ripristinata a partire da uno. Per chiarire questo aspetto, esaminiamo di nuovo la query dell'inizio di questo articolo. SELECT original_language, title, author, sales, RANK() OVER (PARTITION BY original_language ORDER BY sales DESC) AS sales_rank FROM books; In questa query, RANK() viene utilizzato insieme a PARTITION BY. La partizione, in questo caso, è original_language. La classificazione avviene per vendite in ordine decrescente, come specificato nella clausola ORDER BY. Il modo in cui abbiamo scritto PARTITION BY e ORDER BY significa che i libri sono classificati in base alle vendite, ma all'interno di ogni categoria linguistica. Una volta che la funzione ha classificato tutti i libri in una lingua, riparte quando raggiunge la seconda lingua e così via. Lo vediamo nell'output della query. original_languagetitleauthorsalessales_rank EnglishHarry Potter and the Philosopher's StoneJ. K. Rowling1201 EnglishThe HobbitJ. R. R. Tolkien1002 EnglishLolitaVladimir Nabokov503 EnglishWatership DownRichard Adams503 EnglishNineteen Eighty-FourGeorge Orwell305 FrenchThe Little PrinceAntoine de Saint-Exupéry2001 FrenchThe PlagueAlbert Camus122 FrenchThe StrangerAlbert Camus103 ItalianThe Name of the RoseUmberto Eco501 ItalianThe Adventures of PinocchioCarlo Collodi352 ItalianThe Divine ComedyDante Alighieri123 RussianWar and PeaceLeo Tolstoy361 RussianAndromeda NebulaIvan Yefremov202 SpanishDon QuixoteMiguel de Cervantes5001 SpanishOne Hundred Years of SolitudeGabriel García Márquez502 Abbiamo contrassegnato ogni partizione con un colore diverso per vedere facilmente le diverse partizioni. Il libro più venduto in inglese è Harry Potter e la pietra filosofale di J.K. Rowling. Poi c'è Lo Hobbit. Lolita e Watership Down sono entrambi al terzo posto, poiché RANK() assegna lo stesso grado ai libri con lo stesso valore di vendita. Poi si salta un valore di classifica e Diciannove Ottantaquattro è al quinto posto. La partizione successiva riguarda la lingua francese e la classifica ricomincia. Il Piccolo Principe è il libro più venduto in francese. La stessa logica funziona per i libri in italiano, russo e spagnolo. Esempio bonus Abbiamo studiato queste query per mostrare come funziona RANK() OVER (PARTITION BY). Ora facciamo pratica! La seguente non è molto diversa dalla prima query. Non dovreste avere problemi ad applicare ciò che avete imparato. C'è una colonna nella tabella books denominata classify_under. Essa specifica la categoria in cui ogni libro deve essere inserito nella libreria. Classifichiamo i libri in base alle vendite per ogni categoria. SELECT classify_under, title, author, sales, RANK() OVER (PARTITION BY classify_under ORDER BY sales DESC) AS sales_rank FROM books; La query seleziona la colonna classify_under invece di original_language nella prima query. Tutte le altre colonne selezionate sono le stesse. C'è anche una differenza in RANK(). Dal momento che stiamo classificando per classify_under, questa è la colonna che deve essere presente nella clausola PARTITION BY. Ancora una volta, vogliamo classificare i libri in base alle vendite in ordine decrescente. Ecco la classifica: classify_undertitleauthorsalessales_rank ClassicsDon QuixoteMiguel de Cervantes5001 ClassicsLolitaVladimir Nabokov502 ClassicsThe Name of the RoseUmberto Eco502 ClassicsOne Hundred Years of SolitudeGabriel García Márquez502 ClassicsWar and PeaceLeo Tolstoy365 ClassicsNineteen Eighty-FourGeorge Orwell306 ClassicsThe PlagueAlbert Camus127 ClassicsThe StrangerAlbert Camus108 FantasyHarry Potter and the Philosopher's StoneJ. K. Rowling1201 FantasyThe HobbitJ. R. R. Tolkien1002 FantasyWatership DownRichard Adams503 KidsThe Little PrinceAntoine de Saint-Exupéry2001 KidsThe Adventures of PinocchioCarlo Collodi352 PoetryThe Divine ComedyDante Alighieri121 Science fictionAndromeda NebulaIvan Yefremov201 Per pura coincidenza, ci sono di nuovo cinque partizioni. Nella categoria "Classici", Don Chisciotte è il libro più venduto. Poi ci sono tre libri al secondo posto. La sequenza di classifica viene saltata fino ad arrivare a Guerra e pace al quinto posto. Il resto dei classici viene classificato in sequenza, poiché non ci sono più pareggi. In altre categorie, non ci sono pareggi: "Poesia" e "Fantascienza" hanno un solo libro per categoria. Quindi, c'è solo la prima classifica. Per ulteriori esempi con altre funzioni della finestra, consultate il nostro articolo che spiega come utilizzare PARTITION BY. Aggiungere RANK() al vocabolario SQL Abbiamo visto gli usi più tipici della funzione finestra RANK(). Sebbene richieda una OVER (ORDER BY), la clausola PARTITION BY ne sblocca le possibilità. Essa rende RANK() uno strumento sofisticato per classificare i dati in una o più partizioni con facilità nel lavoro quotidiano. Per saperne di più e fare pratica con RANK() e con altre funzioni finestra (di classificazione), utilizzate il nostro corso Window Functions corso. Avrete una spiegazione ancora più dettagliata del ranking e la possibilità di scrivere molto codice nei nostri esercizi. Buona classificazione! Tags: sql rank