20th Jul 2022 Tempo di lettura: 6 minuti Funzioni SQL Window vs. GROUP BY: Qual è la differenza? Ignacio L. Bisso sql imparare sql window functions Indice Rapido ripasso di GROUP BY GROUP BY vs Window Functions Il potere di Window Functions Window Functions contro le funzioni aggregate Chiudere la finestra Un'idea sbagliata molto comune tra gli utenti di SQL è che non ci sia molta differenza tra le funzioni SQL window e le funzioni aggregate o la clausola GROUP BY. Tuttavia, le differenze sono molto significative. Forse l'unico punto in comune tra le funzioni GROUP BY e le funzioni finestra è che entrambe consentono di eseguire una funzione (come AVG, MAX, MIN o COUNT) su un gruppo di record. Direi che il potere speciale delle funzioni finestra è che ci permettono di ottenere risultati che altrimenti sarebbero quasi impossibili da raggiungere. In questo articolo esamineremo l'uso delle funzioni finestra rispetto a GROUP BY e delle funzioni finestra rispetto alle funzioni aggregate. Rapido ripasso di GROUP BY La clausola GROUP BY consente di raggruppare un insieme di record in base ad alcuni criteri e di applicare una funzione (ad esempio AVG o MAX) a ciascun gruppo, ottenendo un risultato per ogni gruppo di record. Vediamo un esempio. Abbiamo una tabella chiamata employee con un totale di cinque dipendenti e tre dipartimenti: Employee_NameDepartmentSalary John RobertsFinance2300 Peter HudsonMarketing1800 Sue GibsonFinance2000 Melinda BishopMarketing1500 Nancy HudsonIT1950 fig1: la tabella dei dipendenti Supponiamo di voler ottenere il salario medio per reparto e il salario massimo per ogni reparto. Dovremmo utilizzare la seguente query: SELECT Department, avg(salary) as average, max(salary) as top_salary FROM employee GROUP BY department L'immagine seguente mostra il risultato: Departmentaveragetop_salary Marketing16501800 Finance21502300 IT19501950 GROUP BY vs Window Functions Quando si confrontano le funzioni finestra e GROUP BY, è essenziale ricordare che GROUP BY comprime i singoli record in gruppi; dopo aver utilizzato GROUP BY, non è possibile fare riferimento a nessun campo individuale perché è compresso. Più avanti parleremo in modo approfondito di questo argomento. Per ora, ci limitiamo a ricordare che le funzioni della finestra non comprimono i singoli record. Quindi, se si vuole creare un report con il nome di un dipendente, il suo stipendio e il massimo stipendio del suo reparto, non è possibile farlo con GROUP BY. I singoli record di ciascun dipendente vengono compressi dalla clausola GROUP BY department. Per questo tipo di report è necessario utilizzare le funzioni di finestra, argomento della prossima sezione. Se volete approfondire le sfumature di SQL GROUP BY e dei report, vi consigliamo il nostro corso interattivo Creating Basic SQL Reports. Il potere di Window Functions Le funzioni finestra sono una potente caratteristica di SQL. Permettono di applicare funzioni come AVG, COUNT, MAX e MIN a un gruppo di record, lasciando comunque accessibili i singoli record. Dal momento che i singoli record non vengono compressi, è possibile creare query che mostrano i dati del singolo record insieme al risultato della funzione finestra. Questo è ciò che rende le funzioni finestra così potenti. Supponiamo di voler ottenere un elenco di nomi di dipendenti, stipendi e lo stipendio più alto nei loro reparti. SELECT employee_name, department, salary, max(salary) OVER (PARTITION BY department) as top_salary FROM employee L'immagine successiva mostra il risultato: Employee_NameDepartmentsalarytop_salary John RobertsFinance23002300 Peter HudsonMarketing18001800 Sue GibsonFinance20002300 Melinda BishopMarketing15001800 Nancy HudsonIT19501950 Nella query precedente, abbiamo usato una funzione finestra: max(salary) OVER (PARTITION BY department) as top_salary La funzione finestra è MAX() e l'abbiamo applicata all'insieme di record definiti dalla clausola OVER (PARTITION BY department)che sono i record con lo stesso valore nel campo reparto. Infine, abbiamo rinominato la colonna top_salary. Nel risultato della query, abbiamo righe per i singoli dipendenti. Se avessimo usato GROUP BY invece delle funzioni finestra, avremmo avuto righe per ogni reparto. Le funzioni finestra hanno una sintassi piuttosto prolissa; se volete approfondire, vi suggerisco il corso "Window Functions", che è un tutorial passo-passo che vi guida attraverso le funzioni finestra di SQL con esempi ed esercizi. Window Functions contro le funzioni aggregate Se confrontiamo le funzioni finestra e le funzioni aggregate, notiamo una caratteristica molto potente delle funzioni finestra: le funzioni posizionali. Esse consentono di ottenere il valore di una colonna da altri record della stessa finestra. Si tratta di una capacità davvero straordinaria, che consente agli utenti di SQL di creare report complessi in poche righe. Vediamo brevemente due di queste funzioni: LEAD() e LAG(). La funzione LAG() restituisce il valore della colonna del record precedente nella finestra, mentre LEAD() restituisce il valore della colonna del record successivo nella finestra. È molto importante che la finestra sia ordinata in base alla colonna di destra se si desidera utilizzare queste funzioni. Vediamo un esempio di utilizzo di queste funzioni. Supponiamo di avere una tabella che contiene le azioni di una società con il loro valore di mercato in un determinato momento. La tabella potrebbe avere questo aspetto: share_symboltimestampvalue OILBEST2020-03-05 10:00120 OILBEST2020-03-05 12:00123 OILBEST2020-03-05 15:00122 BANKWEB2020-03-05 10:0091 BANKWEB2020-03-05 12:0087 BANKWEB2020-03-05 15:0099 fig2: la tabella delle azioni Supponiamo di voler creare un report che mostri il valore di ogni azione con il suo valore precedente e la percentuale di variazione rispetto al valore precedente. Possiamo farlo utilizzando la funzione LEAD() per ottenere il valore precedente dell'azione. Si noti che si usa ORDER BY timestamp quando si definisce la partizione (cioè la finestra dei record). Torneremo su questo punto più avanti. SELECT share_symbol, timestamp, value, LAG(value) OVER (PARTITION BY share_symbol ORDER BY timestamp ) AS previous_value, TRUNC(((value - (LAG(value) OVER (PARTITION BY share_symbol ORDER BY timestamp )))*100)/value,2) AS percentage_variation FROM share Si noti che le colonne previous_value e percentage_variation sono colonne calcolate. Utilizzano valori provenienti da record diversi della stessa tabella. share_symboltimestampvalueprevious_valuepercentage_variation OILBEST2020-03-05 10:00120 OILBEST2020-03-05 12:001231202.43 OILBEST2020-03-05 15:00122123-0.81 BANKWEB2020-03-05 10:0091 BANKWEB2020-03-05 12:008791-4.59 BANKWEB2020-03-05 15:00998712.12 Quando si utilizzano funzioni posizionali, è molto importante inserire una clausola ORDER BY insieme alla clausola PARTITION (come abbiamo fatto nella query precedente). Se non si usa la giusta ORDER BY, i risultati possono essere sbagliati. Perché? Perché le funzioni posizionali lavorano in base all'ordine dei record nella finestra. Esaminiamo meglio questo aspetto. La funzione FIRST_VALUE() restituisce il valore di una colonna dal primo record della finestra. LAG() Come sappiamo, la funzione restituisce il valore della colonna del record precedente nella finestra. L'ordine corretto della finestra è fondamentale; immaginate cosa si otterrebbe altrimenti da queste funzioni! Nel nostro esempio, vogliamo il valore di mercato cronologico precedente per un'azione specifica. Abbiamo quindi utilizzato ORDER BY timestamp. Se omettiamo ORDER BY o ordiniamo per un'altra colonna, il risultato sarebbe sbagliato. In alcuni casi specifici, le funzioni posizionali possono restituire valori errati a causa di una finestra parzialmente popolata. Esistono poi altre funzioni finestra, come RANK(), NTH_VALUE() e LAST_VALUE(). Non c'è spazio per trattare tutto questo in questa sede, ma vi suggerisco di dare un'occhiata a questo articolo che spiega le funzioni finestra e a questi esempi di funzioni finestra per saperne di più. Chiudere la finestra In questo articolo abbiamo esplorato le differenze tra le funzioni finestra e GROUP BY. Abbiamo esaminato esempi con diverse funzioni aggregate e a finestra. Abbiamo anche parlato di un'importante limitazione della clausola GROUP BY, ovvero il "collasso dei record". Questa limitazione non è presente nelle funzioni finestra, consentendo agli sviluppatori SQL di combinare i dati a livello di record con i risultati delle funzioni finestra nella stessa query. Un altro vantaggio delle funzioni finestra è la possibilità di combinare valori di query provenienti da record diversi (della stessa finestra) nella stessa riga del set di risultati. Se siete interessati a saperne di più sulle funzioni finestra, vi suggerisco il corso Window Functions dove è possibile imparare le funzioni finestra di SQL con esercizi interattivi e spiegazioni dettagliate. Tags: sql imparare sql window functions