27th Jul 2023 Tempo di lettura: 15 minuti Come usare SUM() con OVER(PARTITION BY) in SQL Martyna Sławińska sql PARTITION BY window functions Indice La clausola OVER() in SQL Esempio 1A: Calcolo della somma per ciascun gruppo - SUM() con OVER(PARTITION BY ...) Esempio 1B: Calcolo dello stipendio per ciascun titolo di lavoro Esempio 2: Calcolo del rapporto tra il valore di una singola riga e il totale Esempio 2: Calcolo del rapporto tra il valore di una singola riga e il totale Qual è la differenza tra SUM() con OVER(PARTITION BY …) e l'uso di SUM() con GROUP BY? Esempio 3: Calcolo di un totale progressivo usando SUM() con OVER(PARTITION BY) Esempio 4: Conteggio degli oggetti nelle categorie personalizzate Esempio 5: Calcolo del totale di un ordine con sconti usando SUM() con CASE WHEN SOMMA() con OVER() e PARTITION BY Scoprite i casi d'uso reali della funzione SUM() con la clausola OVER(PARTITION BY). Imparate la sintassi e guardate 5 diversi esempi. Utilizziamo le funzioni SQL window per eseguire operazioni su gruppi di dati. Queste operazioni includono le funzioni matematiche SUM(), COUNT(), AVG() e altre ancora. In questo articolo spiegheremo cosa fanno SUM() e OVER(PARTITION BY) in SQL. Vi mostreremo i casi d'uso più comuni nelle applicazioni reali per determinare il rapporto tra il valore di una singola riga e il valore totale, calcolare i totali progressivi e trovare un totale d'ordine personalizzato che includa gli sconti per alcuni prodotti. Per una guida approfondita all'uso di SUM() con OVER() e altre funzioni di finestra, seguite il nostro corso interattivo Window Functions interattivo. Spiega in dettaglio tutti i concetti delle funzioni finestra SQL e contiene oltre 200 esercizi. Iniziamo. La clausola OVER() in SQL In SQL, la clausola OVER() viene utilizzata per introdurre le funzioni finestra. La sintassi generale è: SELECT … <window function> OVER(...) … OVER() indica al database che vogliamo usare le funzioni finestra. La funzione finestra può essere una funzione aggregata, come SUM(), o un'altra funzione finestra. Una funzione finestra lavora su una "cornice di finestre", ovvero un insieme di righe relative alla riga corrente. OVER() definisce la cornice di finestre per ogni riga. Una clausola OVER() vuota indica al database che l'intero insieme di risultati è la cornice della finestra. Vediamo un esempio della sintassi di SUM() OVER(). Utilizzeremo la tabella employees dai dati di esempio forniti da Oracle Live SQL. Questa tabella è composta dalle seguenti colonne: emp_id è l'identificativo del dipendente. name è il nome del dipendente. job è il titolo del lavoro. dept_id è l'identificativo del reparto. salary è lo stipendio del dipendente. EMP_IDNAMEJOBDEPT_IDSALARY 7839KINGPRESIDENT105000 7698BLAKEMANAGER302850 … 7900JAMESCLERK30950 7934MILLERCLERK101300 È possibile utilizzare la funzione SUM() con la clausola OVER() per ottenere lo stipendio totale di tutti i dipendenti e visualizzare lo stipendio totale accanto allo stipendio di ciascun dipendente. SELECT emp_id, name, job, dept_id, salary, SUM(salary) OVER() AS total_salary FROM employees; emp_idNAMEJOBDEPT_IDSALARYTOTAL_SALARY 7839KINGPRESIDENT10500029025 7698BLAKEMANAGER30285029025 … 7900JAMESCLERK3095029025 7934MILLERCLERK10130029025 La funzione SUM() viene eseguita per ogni riga della tabella. Ogni volta che viene richiamata, recupera le informazioni sullo stipendio da tutte le righe della tabella per calcolare l'importo totale dello stipendio. Lo stipendio totale viene visualizzato accanto ai dettagli di ogni singola riga. I dettagli delle singole righe vengono conservati e visualizzati accanto al salario totale. In questo esempio, la finestra (l'insieme di righe su cui opera SUM() ) è l'intero set di dati. È possibile aggiungere altre clausole in OVER() per modificare la cornice della finestra. Esempio 1A: Calcolo della somma per ciascun gruppo - SUM() con OVER(PARTITION BY ...) La clausola OVER() può contenere dettagli sul modo in cui si desidera partizionare i dati. Si usa la clausola PARTITION BY in OVER() per dividere i dati in partizioni, o gruppi. L'uso di PARTITION BY è simile a quello di GROUP BY, in quanto le righe vengono suddivise in gruppi in base al valore di alcune colonne. Quando si usa SUM() OVER(PARTITION BY …), si può calcolare la somma dei valori per ogni gruppo, o partizione, di dati. Ad esempio, è possibile calcolare lo stipendio totale per ogni reparto: SELECT emp_id, name, job, dept_id, salary, SUM(salary) OVER(PARTITION BY dept_id) AS dept_total_salary FROM employees; Ecco il risultato: EMP_IDNAMEJOBDEPT_IDSALARYDEPT_TOTAL_SALARY 7782CLARKMANAGER1024508750 7934MILLERCLERK1013008750 7839KINGPRESIDENT1050008750 7902FORDANALYST20300010875 7788SCOTTANALYST20300010875 7566JONESMANAGER20297510875 7369SMITHCLERK2080010875 7876ADAMSCLERK20110010875 7521WARDSALESMAN3012509400 7654MARTINSALESMAN3012509400 7844TURNERSALESMAN3015009400 7900JAMESCLERK309509400 7499ALLENSALESMAN3016009400 7698BLAKEMANAGER3028509400 Utilizziamo SUM(salary) OVER(PARTITION BY dept_id) per ottenere lo stipendio totale per reparto. La clausola PARTITION BY divide le righe in gruppi in base alla colonna dept_id. Le righe con dept_id uguale a 10 vengono inserite in un gruppo (contrassegnato in giallo nella tabella precedente), le righe con dept_id uguale a 20 vengono inserite in un altro gruppo (contrassegnato in verde) e infine le righe con dept_id uguale a 30 vengono inserite in un altro gruppo (contrassegnato in rosso). La funzione SUM() calcola la somma delle righe in ogni gruppo. Si noti che quando si utilizza SUM() OVER(PARTITION BY), si conservano i dettagli delle singole righe. È possibile, ad esempio, vedere i dettagli del dipendente Ford: la sua posizione, il suo stipendio e il confronto con gli stipendi totali del suo reparto. Questo è l'uso più tipico di SUM() OVER(PARTITION BY): si calcola il valore della somma per ogni gruppo di dati e si conservano i dettagli delle singole righe. Vediamo un esempio simile. Esempio 1B: Calcolo dello stipendio per ciascun titolo di lavoro Possiamo usare SUM(salary) OVER(PARTITION BY job) per ottenere lo stipendio totale per ogni titolo di lavoro. Diamo un'occhiata: SELECT emp_id, name, job, dept_id, salary, SUM(salary) OVER(PARTITION BY job) AS job_total_salary FROM employees; Ecco il risultato: EMP_IDNAMEJOBDEPT_IDSALARYJOB_TOTAL_SALARY 7782CLARKMANAGER1024508275 7698BLAKEMANAGER3028508275 7566JONESMANAGER2029758275 7934MILLERCLERK1013004150 7369SMITHCLERK208004150 7876ADAMSCLERK2011004150 7900JAMESCLERK309504150 7902FORDANALYST2030006000 7788SCOTTANALYST2030006000 7521WARDSALESMAN3012505600 7654MARTINSALESMAN3012505600 7844TURNERSALESMAN3015005600 7499ALLENSALESMAN3016005600 7839KINGPRESIDENT1050005000 Questa volta, le righe sono raggruppate in base al valore della mansione anziché all'ID del reparto. I dipendenti con la stessa posizione lavorativa vengono inseriti in un gruppo e si calcola il salario totale delle persone che occupano questa posizione. La funzione SUM() viene applicata a tutti gli stipendi di ciascun gruppo: lo stipendio totale del gruppo "Manager" è la somma di 2450, 2850 e 2975, che sono gli stipendi dei tre manager presenti nella nostra tabella. Esempio 2: Calcolo del rapporto tra il valore di una singola riga e il totale In genere, si vuole vedere il confronto tra ogni singola riga e la somma totale. Calcoliamo la percentuale di ogni singolo stipendio rispetto al totale degli stipendi del proprio reparto. SELECT emp_id, name, job, dept_id, salary, ROUND(100.0 * salary / SUM(salary) OVER(PARTITION BY dept_id), 2) AS percentage_of_dept_total_salary FROM employees; EMP_IDNAMEJOBDEPT_IDSALARYPERCENTAGE_OF_DEPT_TOTAL_SALARY 7782CLARKMANAGER10245028 7934MILLERCLERK10130014.86 7839KINGPRESIDENT10500057.14 7902FORDANALYST20300027.59 7788SCOTTANALYST20300027.59 7566JONESMANAGER20297527.36 7369SMITHCLERK208007.36 7876ADAMSCLERK20110010.11 7521WARDSALESMAN30125013.3 7654MARTINSALESMAN30125013.3 7844TURNERSALESMAN30150015.96 7900JAMESCLERK3095010.11 7499ALLENSALESMAN30160017.02 7698BLAKEMANAGER30285030.32 Questa volta, le righe sono raggruppate in base al valore job anziché all'ID del reparto. I dipendenti con la stessa posizione lavorativa vengono inseriti in un gruppo e si calcola la retribuzione totale delle persone che occupano questa posizione. La funzione SUM() viene applicata a tutti gli stipendi di ciascun gruppo: lo stipendio totale del gruppo "Manager" è la somma di 2450, 2850 e 2975, che sono gli stipendi dei tre manager presenti nella nostra tabella. Esempio 2: Calcolo del rapporto tra il valore di una singola riga e il totale In genere, si vuole vedere il confronto tra ogni singola riga e la somma totale. Calcoliamo la percentuale di ogni singolo stipendio rispetto al totale degli stipendi del proprio reparto. SELECT emp_id, name, job, dept_id, salary, ROUND(100.0 * salary / SUM(salary) OVER(PARTITION BY dept_id), 2) AS percentage_of_dept_total_salary FROM employees; EMP_IDNAMEJOBDEPT_IDSALARYPERCENTAGE_OF_DEPT_TOTAL_SALARY 7782CLARKMANAGER10245028 7934MILLERCLERK10130014.86 7839KINGPRESIDENT10500057.14 7902FORDANALYST20300027.59 7788SCOTTANALYST20300027.59 7566JONESMANAGER20297527.36 7369SMITHCLERK208007.36 7876ADAMSCLERK20110010.11 7521WARDSALESMAN30125013.3 7654MARTINSALESMAN30125013.3 7844TURNERSALESMAN30150015.96 7900JAMESCLERK3095010.11 7499ALLENSALESMAN30160017.02 7698BLAKEMANAGER30285030.32 Possiamo vedere, ad esempio, che l'analista Scott ha uno stipendio individuale di 3000, pari al 27,59% degli stipendi totali del suo reparto. Ecco la ripartizione delle funzioni utilizzate per svolgere questo compito: Prendiamo ogni singolo stipendio e lo dividiamo per lo stipendio totale del reparto: salary / SUM(salary) OVER(PARTITION BY dept_id) Per ottenere una percentuale, la moltiplichiamo per il 100%: 0 * salary / SUM(salary) OVER(PARTITION BY dept_id) Successivamente, utilizziamo la funzione ROUND() per ottenere due cifre decimali: ROUND(100.0 * salary / SUM(salary) OVER(PARTITION BY dept_id), 2) Il calcolo del rapporto tra la singola riga e la somma di un gruppo è un altro caso d'uso molto comune di SUM() con OVER(PARTITION BY). In modo simile, si può calcolare la differenza tra il totale del gruppo e la singola riga. Qual è la differenza tra SUM() con OVER(PARTITION BY …) e l'uso di SUM() con GROUP BY? La clausola PARTITION BY svolge un compito simile a quello della clausola GROUP BY. Sia OVER(PARTITION BY) che GROUP BY dividono il set di dati in partizioni, o gruppi. Quando si usa la funzione SUM(), entrambe le espressioni calcolano la somma per ogni gruppo. Quindi, quale scegliere? Quando si utilizza la clausola GROUP BY, i dettagli delle singole righe vengono ridotti. Guardate: SELECT job, SUM(salary) AS total_salary FROM employees GROUP BY job; JOBTOTAL_SALARY ANALYST6000 CLERK4150 SALESMAN5600 MANAGER8275 PRESIDENT5000 In questo caso, si ottiene il valore totale dello stipendio per ogni titolo di lavoro senza considerare gli stipendi dei singoli dipendenti. Tuttavia, se si desidera confrontare il valore della somma totale con i valori delle singole righe (ad esempio, per calcolare il rapporto tra il valore individuale e quello totale), la strada da percorrere è OVER(PARTITION BY …), che restituisce tutte le singole righe insieme al valore della somma totale per ogni riga. Il valore della somma totale può variare a seconda della partizione a cui appartiene la riga. SELECT name, job, salary, SUM(salary) OVER(PARTITION BY job) AS total_salary FROM employees; NAMEJOBSALARYTOTAL_SALARY FORDANALYST30006000 SCOTTANALYST30006000 SMITHCLERK8004150 JAMESCLERK9504150 ADAMSCLERK11004150 MILLERCLERK13004150 BLAKEMANAGER28508275 JONESMANAGER29758275 CLARKMANAGER24508275 KINGPRESIDENT50005000 TURNERSALESMAN15005600 ALLENSALESMAN16005600 WARDSALESMAN12505600 MARTINSALESMAN12505600 Il valore total_salary corrisponde ai risultati della query precedente con GROUP BY. Ma qui è possibile vedere anche i singoli stipendi. Ad esempio, ci sono due analisti che guadagnano 6000 in totale; ognuno di loro guadagna 3000. La regola generale è la seguente: se si vuole conoscere solo il valore della somma per ogni gruppo e non si è interessati ai dettagli di ogni singola riga, si deve usare la clausola GROUP BY. Se si è interessati sia alla somma di ciascun gruppo sia ai dettagli delle singole righe, si deve usare la clausola SUM() OVER(PARTITION BY). Esempio 3: Calcolo di un totale progressivo usando SUM() con OVER(PARTITION BY) Un altro uso comune della sintassi SUM() OVER(...) è il calcolo del totale progressivo. Un totale progressivo è la somma cumulativa dei numeri precedenti di una colonna. Si usano i totali progressivi per calcolare valori che si accumulano nel tempo. Ad esempio, con un totale progressivo si può calcolare l'utilizzo mensile dei dati mobili aggiungendo il valore di ogni giorno successivo alla somma dei valori dei giorni precedenti. Allo stesso modo, è possibile calcolare come il numero di utenti registrati aumenti ogni giorno o come le entrate totali aumentino con ogni transazione. Per calcolare il totale progressivo utilizziamo la sintassi SUM() con OVER(PARTITION BY … ORDER BY …). Vediamo un esempio. Utilizzeremo la tabella orders dai dati di esempio forniti da Oracle Live SQL. Questa tabella memorizza i dati storici degli ordini. Ogni ordine ha una data (order_date), un rappresentante (sales_rep_id) e un valore totale (order_total). Qui calcoliamo il valore totale corrente per ogni rappresentante di vendita: SELECT order_date, sales_rep_id, order_total, SUM(order_total) OVER(PARTITION BY sales_rep_id ORDER BY order_date) AS running_total FROM orders; ORDER_DATESALES_REP_IDORDER_TOTALRUNNING_TOTAL 29-MAR-07 02.22.40.536996 PM15310794.610794.6 16-AUG-07 03.34.12.234359 PM15378279.689074.2 04-OCT-07 09.53.34.362632 PM15312989203.2 21-NOV-07 10.22.33.263332 AM15313824103027.2 16-DEC-07 08.19.55.462332 PM15311188.5114215.7 27-JUL-06 12.22.59.662632 PM15452471.952471.9 27-JUL-06 01.34.16.562632 PM154364656117.9 29-JUN-07 09.53.41.984501 AM1544856165.9 01-JUL-07 04.49.13.615512 PM15422056385.9 02-JUL-07 03.34.44.665170 AM15460056985.9 01-SEP-07 09.53.26.934626 AM154545162436.9 02-OCT-07 05.49.34.678340 PM1546653.469090.3 10-NOV-07 03.49.25.526321 AM15450125119215.3 19-NOV-07 02.41.54.696211 PM15442283.2161498.5 17-DEC-07 05.03.52.562632 PM15410474.6171973.1 Per fare ciò, si suddivide la tabella per rappresentante e si ordina ogni suddivisione per data: SUM(order_total) OVER(PARTITION BY sales_rep_id ORDER BY order_date) Il nuovo elemento della sintassi è ORDER BY. Definisce come vengono ordinate le righe in ogni riquadro della finestra. La funzione SUM() viene applicata a ogni riga, sommando il valore attuale order_total al valore precedente running_total; i totali progressivi vengono calcolati separatamente per ogni partizione (in questo caso, per ogni ID rappresentante). Osserviamo più da vicino l'addetto alle vendite con ID 153. Il suo primo ordine è stato effettuato il 29 marzo. Il loro primo ordine è stato effettuato il29 marzo e aveva un valore totale di 10794,6. A questo punto, il totale progressivo (per ogni ID di vendita) è stato calcolato separatamente per ogni partizione. A questo punto, il totale corrente (la somma) è uguale al valore dell'ordine. Il secondo ordine è stato effettuato il16 agosto per un valore di 78279,6; ora il totale corrente è uguale alla somma dei valori del primo e del secondo ordine (10794,6 + 78279,6 = 89074,2). Dopo il terzo ordine, il totale corrente è uguale al totale precedente più il valore del terzo ordine (89074,2 + 129 = 89203,2). Questo processo è simile per l'addetto alle vendite con l'ID 154. Il calcolo di un totale progressivo è uno schema comune quando si utilizza SQL per l'analisi dei dati. Potete leggere come calcolare un totale progressivo in SQL in un'altra parte del blog. Esempio 4: Conteggio degli oggetti nelle categorie personalizzate La funzione SUM() viene spesso abbinata all'istruzione CASE WHEN per contare gli oggetti in categorie personalizzate. Ad esempio, si potrebbe voler calcolare il totale degli stipendi dei dipendenti che occupano posizioni dirigenziali in un reparto e visualizzarlo accanto ai dati di ciascun dipendente. È possibile ottenere questo risultato utilizzando SUM() OVER(PARTITION BY) in combinazione con CASE WHEN. Esaminiamo innanzitutto l'istruzione CASE WHEN. È simile all'istruzione if, comune a molti linguaggi di programmazione. Si usa per definire il valore di un'espressione in situazioni o casi diversi. Nell'esempio seguente, usiamo l'istruzione CASE WHEN per identificare ogni dipendente come dirigente (manager e presidenti) o come dipendente normale (tutte le altre posizioni lavorative). Date un'occhiata: SELECT emp_id, name, job, dept_id, CASE WHEN job IN (‘PRESIDENT’, ‘MANAGER’) THEN ‘MANAGEMENT’ ELSE ‘REGULAR’ END AS emp_type salary FROM employees; L'istruzione CASE valuta tutte le condizioni di WHEN. Se trova la condizione corrispondente, restituisce il valore nel ramo THEN. Se non trova la condizione corrispondente, restituisce il valore indicato dopo ELSE. Nel nostro esempio, i dipendenti che ricoprono la posizione di presidente o manager sono etichettati come "Management". A tutte le altre posizioni lavorative viene assegnata l'etichetta 'Regular'. Ecco il risultato della query: EMP_IDNAMEJOBDEPT_IDEMP_TYPESALARY 7782CLARKMANAGER10MANAGEMENT2450 7934MILLERCLERK10REGULAR1300 7839KINGPRESIDENT10MANAGEMENT5000 7902FORDANALYST20REGULAR3000 7788SCOTTANALYST20REGULAR3000 7566JONESMANAGER20MANAGEMENT2975 7369SMITHCLERK20REGULAR800 7876ADAMSCLERK20REGULAR1100 7521WARDSALESMAN30REGULAR1250 7654MARTINSALESMAN30REGULAR1250 7844TURNERSALESMAN30REGULAR1500 7900JAMESCLERK30REGULAR950 7499ALLENSALESMAN30REGULAR1600 7698BLAKEMANAGER30MANAGEMENT2850 Per saperne di più su CASE, leggete il nostro articolo Come usare CASE in SQL. È inoltre possibile utilizzare l'istruzione CASE con SUM() per sommare i valori delle categorie personalizzate. Ecco la query: SELECT dept_id, SUM( CASE WHEN job IN (‘PRESIDENT’, ‘MANAGER’) THEN salary ELSE 0 END) AS dept_management_salary, SUM( CASE WHEN job IN (‘PRESIDENT’, ‘MANAGER’) THEN 0 ELSE salary END) AS dept_regular_salary FROM employees GROUP BY dept_id; DEPT_IDDEPT_MANAGEMENT_SALARYDEPT_REGULAR_SALARY 1074501300 2029757900 3028506550 Per i dipendenti in posizione dirigenziale, la prima istruzione CASE restituisce il valore della colonna salary. La funzione SUM() in combinazione con GROUP BY somma quindi tutti gli stipendi dei dipendenti con mansioni dirigenziali con la stessa dept_id. In questo modo, si calcola lo stipendio totale dei dirigenti per reparto. La seconda istruzione CASE calcola lo stipendio totale del reparto per tutti i dipendenti regolari. È possibile calcolare lo stipendio totale dei dipendenti in posizione dirigenziale in un reparto e visualizzarlo accanto ai dettagli dei dipendenti utilizzando SUM() con PARTITION BY: SELECT emp_id, name, job, dept_id, CASE WHEN job IN (‘PRESIDENT’, ‘MANAGER’) THEN ‘MANAGEMENT’ ELSE ‘REGULAR’ END AS emp_type salary, SUM( CASE WHEN job IN (‘PRESIDENT’, ‘MANAGER’) THEN salary ELSE 0 END) OVER(PARTITION BY dept_id) AS dept_management_salary FROM employees; EMP_IDNAMEJOBDEPT_IDEMP_TYPESALARYDEPT_MANAGEMENT_SALARY 7782CLARKMANAGER10MANAGEMENT24507450 7934MILLERCLERK10REGULAR13007450 7839KINGPRESIDENT10MANAGEMENT50007450 7902FORDANALYST20REGULAR30002975 7788SCOTTANALYST20REGULAR30002975 7566JONESMANAGER20MANAGEMENT29752975 7369SMITHCLERK20REGULAR8002975 7876ADAMSCLERK20REGULAR11002975 7521WARDSALESMAN30REGULAR12502850 7654MARTINSALESMAN30REGULAR12502850 7844TURNERSALESMAN30REGULAR15002850 7900JAMESCLERK30REGULAR9502850 7499ALLENSALESMAN30REGULAR16002850 7698BLAKEMANAGER30MANAGEMENT28502850 Le righe vengono suddivise in gruppi in base alla colonna dept_id. Ci sono tre gruppi, uno per ogni reparto. La funzione SUM() viene applicata all'espressione CASE WHEN. Invece di calcolare il salario totale di ogni reparto, si calcola il salario totale dei dipendenti con posizioni dirigenziali nel reparto. La funzione CASE restituisce 0 per i dipendenti regolari (la somma non viene incrementata) e il valore dello stipendio per i dipendenti dirigenti. Questo schema può essere utilizzato in molte situazioni diverse. Infatti, nella prossima sezione vedremo un altro esempio di combinazione di CASE WHEN con SUM() e OVER(PARTITION BY). Esempio 5: Calcolo del totale di un ordine con sconti usando SUM() con CASE WHEN In questo esempio, vogliamo calcolare il valore totale di ogni ordine, compresi gli sconti per alcuni articoli dell'ordine. Utilizzeremo la sintassi SUM() OVER(PARTITION BY …) per sommare tutti i valori degli articoli per ordine. Per incorporare gli sconti sui prodotti, utilizzeremo l'istruzione CASE WHEN. Utilizziamo la tabella order_items dai dati di esempio forniti da Oracle Live SQL. Questa tabella memorizza tutti gli articoli dell'ordine (product_id) appartenenti a ciascun ordine (order_id). Contiene informazioni sul prezzo unitario del prodotto (unit_price) e sulla quantità dell'ordine (quantity). Ora vogliamo calcolare i valori dell'ordine: uno per ogni prodotto dell'ordine e un totale per l'ordine; il totale dell'ordine deve includere eventuali sconti applicati ai prodotti. Il totale dell'ordine è uguale al prezzo unitario moltiplicato per la quantità dell'ordine. Tuttavia, quando viene applicato uno sconto a un prodotto, si utilizzerà un prospetto CASE WHEN per tenerne conto. SELECT order_id, product_id, unit_price, quantity, SUM(CASE -- 20% discount for this product WHEN product_id = 3143 THEN unit_price*quantity*0.8 -- 40% discount for this product WHEN product_id = 3106 THEN unit_price*quantity*0.6 ELSE unit_price*quantity END) OVER(PARTITION BY order_id, product_id) AS order_product_total_with_discount, SUM(CASE -- 20% discount for this product WHEN product_id = 3143 THEN unit_price*quantity*0.8 -- 40% discount for this product WHEN product_id = 3106 THEN unit_price*quantity*0.6 ELSE unit_price*quantity END) OVER(PARTITION BY order_id) AS order_total_with_discount FROM order_items; ORDER_IDPRODUCT_IDUNIT_PRICEQUANTITYORDER_PRODUCT_TOTAL_WITH_DISCOUNTORDER_TOTAL_WITH_DISCOUNT 2354310648611756.844916.2 2354311496.8434162.444916.2 235431237947371344916.2 235431294147192744916.2 235431392148100844916.2 235431431653678.444916.2 23543150175898644916.2 235431633061183044916.2 235431653764236844916.2 235431675168346844916.2 23543170145.2701016444916.2 23543176113.3728157.644916.2 235431826177469744916.2 2355228946200920094513.5 23552308571851054594513.5 2355231186.918816337.294513.5 2355232219188357294513.5 2355232317190323094513.5 235523261.1192211.294513.5 235523301.1197216.794513.5 2355233925199497594513.5 23552359226.620446226.494513.5 Per calcolare il totale per prodotto in un ordine, si utilizza la seguente sintassi: SUM(CASE WHEN product_id=3143 THEN unit_price*quantity*0.8 -- 20% discount WHEN product_id=3106 THEN unit_price*quantity*0.6 -- 40% discount ELSE unit_price*quantity END) OVER(PARTITION BY order_id, product_id) AS order_product_total_with_discount Passiamo l'istruzione CASE WHEN come argomento alla funzione SUM(); se l'ID prodotto della riga corrente è 3143, applichiamo uno sconto del 20%; per l'ID prodotto 3106, lo sconto è del 40%. Successivamente, si suddivide il set di dati in base all'ID dell'ordine e all'ID del prodotto per ottenere i valori totali di ciascun prodotto di un ordine. Si noti che nella query vengono utilizzate due clausole PARTITION BY diverse. Per calcolare il valore totale del prodotto, si partiziona il set di dati per ID ordine e ID prodotto. Per calcolare il totale per ordine, si partiziona il set di dati solo per ID ordine. Il valore totale dell'ordine è uguale per tutte le righe con lo stesso ID ordine. Cioè, se si sommano tutti i valori totali dei prodotti di un determinato ordine, si ottiene il valore totale dell'ordine. Ad esempio, per l'ID ordine 2355, si ottiene quanto segue: 9200 + 10545 + 16337.2 + 3572 + 3230 + 211.2 + 216.7 + 4975 + 46226.4 = 94513.5. Ecco alcuni esempi della funzione SUM() con CASE WHEN. SOMMA() con OVER() e PARTITION BY Ora che sapete come utilizzare la funzione SOMMA() e le sue varie opzioni di sintassi, potete provarla voi stessi. Abbiamo presentato esempi su come calcolare una percentuale del valore di una singola riga rispetto al totale della partizione e abbiamo mostrato come calcolare il totale corrente e il totale dell'ordine personalizzato. Vi invitiamo a fare pratica con i vostri dati. Per saperne di più, provate il nostro corso interattivo Window Functions che spiega in dettaglio tutti i concetti delle funzioni delle finestre. Oppure date un'occhiata al nostro Window Functions Cheat Sheet se volete un riferimento rapido e semplice per le funzioni finestra di SQL. Buona fortuna! Tags: sql PARTITION BY window functions