Aby efektywnie budować agregacje z filtrowaniem według "poziomów" (na przykład najpierw filtrując, a następnie obliczając sumy w grupach, a potem w całym zbiorze), używane są funkcje okienne (OVER()) i zagnieżdżone GROUP BY.
Przykład: Znajdziemy maksymalną sumę zamówienia dla każdego menedżera, ale tylko wśród zamówień o statusie 'paid', a następnie wyprowadźmy imię menedżera z absolutnym maksimum wśród wszystkich.
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;
Takie podejście (CTE + funkcje okienne) pozwala na realizację wielopoziomowego filtrowania i agregacji.
Pułapka: "Czym różni się wykonanie filtru WHERE przed grupowaniem (GROUP BY) od zastosowania HAVING po? Jak to często przyczynia się do błędów w raportach?"
Odpowiedź: WHERE odrzuca wiersze jeszcze przed grupowaniem, co daje ścisły zestaw wejściowy. HAVING filtruje zagregowane grupy — dlatego może tymczasowo "zostawić" zbędne wiersze, jeśli filtr logicznie nie jest zgodny. Niewłaściwe miejsce filtra często prowadzi do błędów w końcowych agregatach lub nieprawidłowych wyników raportów.
-- Uzyskujemy sumę tylko dla 'paid', przez WHERE SELECT ManagerID, SUM(OrderAmount) FROM Orders WHERE Status = 'paid' GROUP BY ManagerID; -- Lub obliczamy sumy dla wszystkich, a potem tniemy HAVING SELECT ManagerID, SUM(OrderAmount) FROM Orders GROUP BY ManagerID HAVING SUM(OrderAmount) > 1000;
Historia
Projekt: Raporty sprzedażowe, audyt weryfikacyjny.
Błąd: Deweloper zastosował HAVING Status='paid' zamiast WHERE, agregaty błędnie uwzględniały również nieopłacone zamówienia, przez co błędnie obliczano roczne KPI personelu.
Historia
Projekt: Analiza bankowa.
Błąd: Do skomplikowanej agregacji próbowano zastosować funkcję okienną bez PARTITION BY, przez co agregaty były obliczane na całej tabeli zamiast w grupie. Budżet departamentu został obliczony niepoprawnie — konieczne było ręczne przywracanie.
Historia
Projekt: Sklep internetowy, statystyki zamówień.
Błąd: Zagnieżdżenie funkcji okiennych w podzapytaniu nie zostało uwzględnione podczas optymalizacji — przez co serwer dokonywał wielokrotnej obróbki danych, a zapytanie działało 20 razy wolniej niż prosta operacja z podwójnym GROUP BY.