Per costruire aggregazioni in modo efficace con filtraggio a "livelli" (ad esempio, prima filtriamo, poi calcoliamo somme per gruppi, e infine per l'intero insieme), si utilizzano le funzioni di finestra (OVER()) e GROUP BY annidati.
Esempio: Troveremo la somma massima degli ordini per ciascun manager, ma solo tra gli ordini con stato 'paid', e quindi mostreremo il nome del manager con la massima somma assoluta tra tutti.
WITH PaidOrders AS ( SELECT ManagerID, SUM(OrderAmount) AS TotalPaid FROM Orders WHERE Status = 'paid' GROUP BY ManagerID ), WithMax AS ( SELECT *, MAX(TotalPaid) OVER() AS MaxTotalPaid FROM PaidOrders ) SELECT ManagerID, TotalPaid FROM WithMax WHERE TotalPaid = MaxTotalPaid;
Questo approccio (CTE + funzioni di finestra) consente di realizzare filtraggio e aggregazione multilivello.
Trucco: "Qual è la differenza tra l'esecuzione del filtro WHERE prima del raggruppamento (GROUP BY) e l'applicazione di HAVING dopo? Come si traduce spesso questo nei report?"
Risposta: WHERE scarta le righe prima del raggruppamento, quindi fornisce un insieme di ingresso rigoroso. HAVING filtra i gruppi aggregati — perciò può temporaneamente "lasciare" righe superflue se il filtro non è logicamente compatibile. Un posizionamento errato del filtro porta spesso a errori nei risultati aggregati finali o a risultati errati nei report.
-- Otteniamo la somma solo su 'paid', tramite WHERE SELECT ManagerID, SUM(OrderAmount) FROM Orders WHERE Status = 'paid' GROUP BY ManagerID; -- Oppure calcoliamo le somme su tutti, e poi tagliamo con HAVING SELECT ManagerID, SUM(OrderAmount) FROM Orders GROUP BY ManagerID HAVING SUM(OrderAmount) > 1000;
Storia
Progetto: Report di vendita, audit di verifica.
Errore: Lo sviluppatore ha applicato HAVING Status='paid' invece di WHERE, le aggregazioni includevano erroneamente anche gli ordini non pagati, il che ha portato a errate valutazioni annuali delle KPI del personale.
Storia
Progetto: Analisi bancaria.
Errore: In una complessa aggregazione si è tentato di applicare una funzione di finestra senza PARTITION BY, il che ha portato a calcoli degli aggregati sull'intera tabella invece che sul gruppo. Il budget del dipartimento è stato calcolato in modo errato — è stato necessario ripristinarlo manualmente.
Storia
Progetto: Negozio online, statistiche sugli ordini.
Errore: L'incapsulamento delle funzioni di finestra in una sottoquery non è stato considerato durante l'ottimizzazione — a causa di ciò, il server ha effettuato elaborazioni ripetute dei dati, la query è diventata 20 volte più lenta rispetto a una semplice con doppio GROUP BY.