Agregacja z warunkami to klasyczne zadanie dla raportowania. Początkowo do obliczania różnych wskaźników tworzono oddzielne zapytania z filtrami. Wkrótce pojawiło się bardziej kompaktowe rozwiązanie — agregacja warunkowa z użyciem CASE wewnątrz funkcji agregujących (np. SUM(CASE WHEN ...)). Problem pojawia się przy łączeniu filtrów, grupowania i nagłówków wyników: łatwo można uzyskać błędne sumy lub błędnie zinterpretować wynik.
Rozwiązanie: używać agregacji warunkowej wewnątrz funkcji agregujących. Na przykład, aby wyświetlić dla wszystkich pracowników liczbę zamówień "w trakcie" i "zakończone":
SELECT employee_id, SUM(CASE WHEN status = 'processing' THEN 1 ELSE 0 END) as processing_count, SUM(CASE WHEN status = 'done' THEN 1 ELSE 0 END) as done_count FROM Orders GROUP BY employee_id;
Kluczowe cechy:
Co się stanie, jeśli warunek CASE zwróci NULL zamiast 0?
Funkcja agregująca SUM ignoruje NULL. Dlatego, jeśli napiszemy CASE WHEN ... THEN 1 END, pominięte wiersze nie zostaną uwzględnione. Lepiej zawsze wyraźnie ustawiać ELSE 0.
SUM(CASE WHEN status = 'processing' THEN 1 ELSE 0 END)
Czy filtr WHERE może zmienić łączną sumę według statusów przy agregacji warunkowej?
Tak: jeśli główny filtr WHERE ogranicza wybór (na przykład, WHERE region = 'west'), obliczenia będą prowadzone tylko na przefiltrowanych danych. Dla globalnych wyników użyj podzapytania lub usuń filtr.
Czy można użyć HAVING do filtrowania wierszy przed grupowaniem?
Nie. HAVING filtruje już zgrupowane dane według agregatów. Filtrowanie oryginalnych wierszy — przez WHERE.
W raporcie analitycznym użyto:
SUM(CASE WHEN status = 'approved' THEN 1 END)
Było dużo NULL, łączone sumy były zaniżone. Z powodu filtru WHERE część potrzebnych wierszy została utracona.
Zalety:
Wady:
Użyto:
SUM(CASE WHEN status = 'approved' THEN 1 ELSE 0 END)
Kod utrzymywano w jednym zapytaniu, filtry na wynik — przez HAVING.
Zalety:
Wady: