18th Jul 2022 Tempo di lettura: 11 minuti 5 esempi pratici di utilizzo della clausola ROWS BETWEEN in SQL Kateryna Koidan sql imparare sql Window Functions Indice Clausola ROWS: Sintassi e opzioni 5 Esempi pratici di utilizzo di ROWS in Window Functions Esempio 1 Esempio 2 Esempio 3 Esempio 4 Esempio 5 Esercitarsi a usare le righe in SQL Window Functions Le funzioni SQL a finestra sono estremamente utili per calcolare aggregazioni complesse come le medie mobili o i totali progressivi. La clausola ROWS permette di specificare le righe per i calcoli, consentendo di creare finestre ancora più sofisticate. Ecco cinque esempi pratici di utilizzo della clausola ROWS BETWEEN in SQL. Lefunzioni finestra (chiamate anche funzioni OVER) calcolano il risultato in base a una finestra scorrevole (cioè un insieme di righe). Sono simili alle funzioni aggregate, in quanto possono calcolare la media, il totale o il valore minimo/massimo di un gruppo di righe. Tuttavia, vi sono alcune importanti differenze: Le funzioni finestra non comprimono le righe come le funzioni aggregate. Pertanto, è ancora possibile mescolare gli attributi di una singola riga con i risultati di una funzione finestra. Lefunzioni finestra consentono di scorrere le cornici della finestra, il che significa che l'insieme delle righe utilizzate per il calcolo di una funzione finestra può essere diverso per ogni singola riga. La sintassi di una funzione finestra è mostrata nel testo blu qui sotto: SELECT , , OVER ( PARTITION BY <...> ORDER BY <...> ) FROM ; Quando si utilizza una funzione finestra nell'istruzione SELECT, in pratica si calcola un'altra colonna con questa funzione: Si inizia specificando una funzione (ad esempio AVG(), SUM(), o COUNT()). Quindi, si utilizza la parola chiave OVER per definire un insieme di righe. Opzionalmente, è possibile: Raggruppate le righe con PARTITION BY in modo che le funzioni vengano calcolate all'interno di questi gruppi invece che nell'intero insieme di righe. Ordinare le righe all'interno di un riquadro di finestra usando ORDER BY se l'ordine delle righe è importante (ad esempio per il calcolo dei totali). Specificare la relazione del riquadro della finestra con la riga corrente (ad esempio, il riquadro deve essere la riga corrente e le due precedenti, oppure la riga corrente e tutte le righe successive, ecc.) Una cornice viene definita utilizzando le clausole ROWS, RANGE e GROUPS. In questo articolo ci concentreremo sulla clausola ROWS e sulle sue opzioni. Per saperne di più sulle funzioni finestra e sulla definizione dei riquadri finestra, consultate questo articolo con esempi di funzioni finestra, questa guida esplicativa e, naturalmente, il nostro foglio informativo di due pagine su SQL Window Functions . Clausola ROWS: Sintassi e opzioni Lo scopo della clausola ROWS è quello di specificare la cornice della finestra in relazione alla riga corrente. La sintassi è la seguente: ROWS BETWEEN lower_bound AND upper_bound I limiti possono essere una qualsiasi delle cinque opzioni seguenti: UNBOUNDED PRECEDING - Tutte le righe prima della riga corrente. n PRECEDING - n righe prima della riga corrente. CURRENT ROW - Solo la riga corrente. n FOLLOWING - n righe dopo la riga corrente. UNBOUNDED FOLLOWING - Tutte le righe dopo la riga corrente. Fonte: SQL Window Functions Cheat Sheet Ecco un paio di cose da tenere a mente quando si definiscono le cornici delle finestre con la clausola ROWS: La cornice della finestra viene valutata separatamente all'interno di ogni partizione. L'opzione predefinita dipende dall'uso di ORDER BY: Con ORDER BY, la cornice predefinita è RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. Senza ORDER BY, la cornice predefinita è ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING. Se uno dei limiti è una riga corrente, è possibile non specificare questo limite e utilizzare una versione più breve della definizione della cornice della finestra: UNBOUNDED PRECEDING è uguale a BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. n PRECEDING è uguale a BETWEEN n PRECEDING AND CURRENT ROW. n FOLLOWING è lo stesso di BETWEEN CURRENT ROW AND n FOLLOWING. UNBOUNDED FOLLOWING è la stessa di BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING. Passiamo agli esempi per vedere come funziona in pratica. 5 Esempi pratici di utilizzo di ROWS in Window Functions Esempio 1 Per iniziare a usare la clausola ROWS, utilizzeremo la seguente tabella con i dati di vendita di una libreria. sales record_iddaterevenue 12021-09-011515.45 22021-09-022345.35 32021-09-03903.99 42021-09-042158.55 52021-09-051819.80 Nel nostro primo esempio, vogliamo aggiungere un'altra colonna che mostri il ricavo totale dalla prima data fino alla data della riga corrente (cioè il totale corrente). Ecco la query da utilizzare: SELECT date, revenue, SUM(revenue) OVER ( ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) running_total FROM sales ORDER BY date; Per calcolare il totale corrente utilizzando una funzione finestra, si procede come segue: Calcolo del totale delle entrate con la funzione aggregata SUM(). Ordinare i record nel riquadro della finestra in base alla data (l'ordine predefinito è ascendente), poiché l'ordine delle righe è importante quando si calcola un totale progressivo. Specificare la cornice della finestra definendo il limite inferiore come UNBOUNDED PRECEDING e il limite superiore come CURRENT ROW. Questo includerà tutte le righe fino a quella corrente. Si noti che il comportamento predefinito senza la clausola ROWS sarebbe lo stesso in questo caso. Il frame predefinito utilizza RANGE e non ROWS. Poiché ogni giorno compare una sola volta nella tabella, il risultato sarà lo stesso per RANGE e ROWS. Si può quindi utilizzare la seguente query per ottenere gli stessi risultati: SELECT date, revenue, SUM(revenue) OVER ( ORDER BY date) running_sum FROM sales ORDER BY date; daterevenuerunning_total 2021-09-011515.451515.45 2021-09-022345.353860.80 2021-09-03903.994764.79 2021-09-042158.556923.34 2021-09-051819.808743.14 Come si vede, la query ha funzionato come previsto e abbiamo ottenuto il totale corrente nella terza colonna. Il primo giorno equivale alle vendite di questo giorno - 1515,45 dollari; il secondo giorno equivale alla somma delle vendite del primo e del secondo giorno - 3860,80 dollari; nella riga successiva otteniamo la somma delle vendite dei primi tre giorni - 4764,79 dollari, ecc. Nei prossimi esempi vedremo come funziona la clausola ROWS quando i record sono divisi in più gruppi. Per esercitarsi a definire le cornici delle finestre, consultate questo corso interattivo con Window Functions con oltre 200 sfide di codifica. Esempio 2 Per i prossimi due esempi, utilizzeremo la tabella seguente. Essa contiene dati fittizi sulla temperatura media (in °C) e sulle precipitazioni totali (in mm) in due città italiane (Roma e Firenze) per cinque giorni consecutivi. weather record_iddatecitytemperatureprecipitation 1012021-09-01Rome18.57 1022021-09-01Florence17.35 1032021-09-02Rome18.020 1042021-09-02Florence17.015 1052021-09-03Rome20.112 1062021-09-03Florence19.010 1072021-09-04Rome20.20 1082021-09-04Florence19.60 1092021-09-05Rome22.50 1102021-09-05Florence20.40 Vogliamo calcolare la temperatura media mobile a tre giorni separatamente per ogni città. Per separare i calcoli per le due città, includeremo la clausola PARTITION BY. Poi, quando specifichiamo la finestra, consideriamo il giorno corrente e i due giorni precedenti: Notate anche che abbiamo inserito la nostra funzione finestra all'interno della funzione ROUND() in modo che la media mobile a tre giorni venga arrotondata a un decimale. Ecco il risultato: citydatetemperaturemov_avg_3d_city Florence2021-09-0117.317.3 Florence2021-09-0217.617.5 Florence2021-09-0319.018.0 Florence2021-09-0419.618.7 Florence2021-09-0520.419.7 Rome2021-09-0118.518.5 Rome2021-09-0219.018.8 Rome2021-09-0320.119.2 Rome2021-09-0420.219.8 Rome2021-09-0522.520.9 La media mobile è stata calcolata separatamente per Firenze e Roma. Per il 1° settembre, la media mobile è uguale alla temperatura media giornaliera, poiché non abbiamo alcun record precedente. Poi, il 2 settembre, la media mobile è calcolata come la temperatura media dell'1 e del 2 (17,5 °C a Firenze e 18,8 °C a Roma, rispettivamente). Il 3 settembre si hanno finalmente dati sufficienti per calcolare la temperatura media di tre giorni (i due precedenti e il giorno in corso), che risulta essere di 18,0 °C a Firenze e 19,2 °C a Roma. Quindi, la media mobile di tre giorni per il 4 settembre viene calcolata come media delle temperature del 2, 3 e 4, e così via. Un'altra cosa da notare: l'ordine dei record nella finestra ha un ruolo fondamentale nello specificare quali righe considerare. Nella query qui sopra, abbiamo ordinato i record nella finestra per data in ordine crescente (utilizzando l'impostazione predefinita), cioè partendo dalla data più antica. Poi, per includere nei nostri calcoli due giorni prima del giorno corrente, abbiamo impostato il limite inferiore come 2 PRECEDING. Tuttavia, si può ottenere la stessa finestra ordinando i record in ordine decrescente e modificando l'opzione ROWS per includere 2 FOLLOWING invece di 2 PRECEDING: SELECT city, date, temperature, ROUND(AVG(temperature) OVER ( PARTITION BY city ORDER BY date DESC ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING), 1) mov_avg_3d_city FROM weather ORDER BY city, date; Questa query produce lo stesso identico risultato. Esempio 3 In questo esempio, calcoleremo le precipitazioni totali degli ultimi tre giorni (cioè un totale di tre giorni) separatamente per due città. SELECT city, date, precipitation, SUM(precipitation) OVER ( PARTITION BY city ORDER BY date ROWS 2 PRECEDING) running_total_3d_city FROM weather ORDER BY city, date; In questa query, i dati vengono nuovamente suddivisi per città. Utilizziamo la funzione SUM() per calcolare il livello totale delle precipitazioni degli ultimi tre giorni, compreso il giorno corrente. Inoltre, si noti che si utilizza un'abbreviazione per definire la finestra specificando solo il limite inferiore: 2 PRECEDING. Ecco l'output della query di cui sopra: citydateprecipitationrunning_total_3d_city Florence2021-09-0155 Florence2021-09-021520 Florence2021-09-031030 Florence2021-09-04025 Florence2021-09-05010 Rome2021-09-0177 Rome2021-09-022027 Rome2021-09-031239 Rome2021-09-04032 Rome2021-09-05012 Al 3 settembre, otteniamo un totale di tre giorni di precipitazioni a Firenze: 30 mm. Si tratta della somma dei 5 mm di precipitazione del 1° settembre, dei 15 mm del 2° e dei 10 mm del 3°. Sapete come abbiamo ottenuto il totale progressivo di 12 mm per Roma il 5 settembre? Provate a seguire i risultati nella nostra tabella di output per assicurarvi di aver capito come funzionano le funzioni delle finestre con i telai specifici delle finestre. Passiamo ora a nuovi dati ed esempi. Esempio 4 Per i prossimi due esempi utilizzeremo i dati mostrati di seguito. Questi dati includono informazioni giornaliere sul numero di nuovi iscritti a tre social network: Instagram, Facebook e LinkedIn. subscribers record_iddatesocial_networknew_subscribers 112021-09-01Instagram40 122021-09-01Facebook12 132021-09-01LinkedIn5 142021-09-02Instagram67 152021-09-02Facebook23 162021-09-02LinkedIn2 172021-09-03Instagram34 182021-09-03Facebook25 192021-09-03LinkedIn10 202021-09-04Instagram85 212021-09-04Facebook28 222021-09-04LinkedIn20 Cominciamo a calcolare i totali progressivi del numero di nuovi iscritti separatamente per ogni rete. In pratica, per ogni giorno, vogliamo vedere quante persone si sono iscritte da quando abbiamo iniziato a raccogliere i dati fino alla data della riga corrente. Ecco una query SQL che soddisfa questa richiesta: SELECT social_network, date, new_subscribers, SUM(new_subscribers) OVER ( PARTITION BY social_network ORDER BY date ROWS UNBOUNDED PRECEDING) running_total_network FROM subscribers ORDER BY social_network, date; Si inizia calcolando il numero totale di nuovi iscritti utilizzando la funzione aggregata SUM(). Quindi si utilizza la clausola PARTITION BY per effettuare calcoli separati per ogni rete. Inoltre, ordiniamo i record per data in ordine crescente (per impostazione predefinita). Infine, definiamo la cornice della finestra come UNBOUNDED PRECEDING per includere tutti i record fino a quello corrente. L'output appare come segue: datesocial_networknew_subscribersrunning_total_network 2021-09-01Facebook1212 2021-09-02Facebook2335 2021-09-03Facebook2560 2021-09-04Facebook2888 2021-09-01Instagram4040 2021-09-02Instagram67107 2021-09-03Instagram34141 2021-09-04Instagram85226 2021-09-01LinkedIn55 2021-09-02LinkedIn27 2021-09-03LinkedIn1017 2021-09-04LinkedIn2037 Nella tabella dei risultati, si può notare come il numero di nuovi iscritti venga aggiunto al totale cumulativo per ogni nuovo record. Il totale progressivo viene calcolato separatamente per ogni rete, come specificato nella funzione finestra. Esempio 5 Nell'ultimo esempio, vogliamo dimostrare come sia possibile visualizzare il primo e l'ultimo valore di una serie specifica di record utilizzando le funzioni finestra e la clausola ROWS. Questa volta aggiungiamo due colonne all'output: Il numero di nuovi abbonati aggiunti il primo giorno, e Il numero di nuovi iscritti aggiunti l'ultimo giorno. Con queste informazioni calcolate separatamente per ogni social network, possiamo vedere come le prestazioni di ogni giorno si confrontano con il punto di partenza e con il punto di arrivo. Ecco la query SQL per ottenere l'output richiesto: SELECT social_network, date, new_subscribers, FIRST_VALUE(new_subscribers) OVER( PARTITION BY social_network ORDER BY date) AS first_day, LAST_VALUE(new_subscribers) OVER( PARTITION BY social_network ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_day FROM subscribers ORDER BY social_network, date; Come si vede, utilizziamo le funzioni FIRST_VALUE() e LAST_VALUE() per ottenere le informazioni rispettivamente sul primo e sull'ultimo giorno. Si noti anche come viene specificata la cornice della finestra per ciascuna delle funzioni: Non includiamo la clausola ROWS con la funzione FIRST_VALUE() perché il comportamento predefinito (cioè RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) va bene per i nostri scopi. Tuttavia, specifichiamo il riquadro della finestra con la funzione LAST_VALUE() perché l'opzione predefinita utilizzerebbe il valore della riga corrente come ultimo valore per ogni record; non è quello che stiamo cercando in questo esempio. Specifichiamo la cornice della finestra come ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING per assicurarci che tutti i record vengano considerati. Ecco l'insieme dei risultati: datesocial_networknew_subscribersfirst_daylast_day 2021-09-01Facebook121228 2021-09-02Facebook231228 2021-09-03Facebook251228 2021-09-04Facebook281228 2021-09-01Instagram404085 2021-09-02Instagram674085 2021-09-03Instagram344085 2021-09-04Instagram854085 2021-09-01LinkedIn5520 2021-09-02LinkedIn2520 2021-09-03LinkedIn10520 2021-09-04LinkedIn20520 Come richiesto, abbiamo il numero di nuovi iscritti del primo e dell'ultimo giorno calcolato separatamente per ogni social network. Esercitarsi a usare le righe in SQL Window Functions Dopo aver esaminato gli esempi precedenti, si spera che si sia motivati a imparare più a fondo le funzioni finestra di SQL e le opzioni ROWS. Questo toolkit consente di specificare una finestra scorrevole e di calcolare aggregazioni complesse come le medie mobili e i totali progressivi. Se volete acquisire familiarità con le funzioni a finestra, vi consiglio il corso interattivo di LearnSQL.itWindow Functions di . Vi mostrerà come calcolare totali e medie consecutive, costruire diversi tipi di classifiche, analizzare le tendenze nel tempo e molto altro ancora. Inoltre, gli esercizi vengono svolti da soli, il che è il modo migliore per imparare. Se volete imparare a usare SQL per l'analisi dei dati, il nostro percorso di apprendimento include anche Advanced SQL percorso di apprendimento include anche GROUP BY Extensions in SQL e le espressioni di tabella comuni (CTE). È un ottimo modo per approfondire la conoscenza delle funzioni di finestra. Volete iniziare a leggere qualcosa? Ecco gli 8 articoli più importanti sulle funzioni finestra di SQL. Grazie per aver letto e buon apprendimento. Tags: sql imparare sql Window Functions