CodeGym /Kursy /SQL SELF /Filtrowanie danych zagregowanych z HAVING

Filtrowanie danych zagregowanych z HAVING

SQL SELF
Poziom 8 , Lekcja 1
Dostępny

O czym jeszcze nie gadaliśmy, to jak przefiltrować grupy po zastosowaniu agregatów? Czasem nie potrzebujemy wszystkich wydziałów — tylko te, gdzie studentów jest ponad setka. Albo chcemy zobaczyć tylko te działy, gdzie średnia pensja przekracza 50 000. Dzisiaj poznasz filtrowanie danych zagregowanych za pomocą HAVING.

Po co nam HAVING, skoro mamy WHERE? Przecież można po prostu wrzucić WHERE po GROUP BY :)

To nie takie proste! Po pierwsze, kolejność operatorów w SQL jest sztywna i WHERE wykonuje się przed GROUP BY.

A może da się go przesunąć po GROUP BY?

Też nie! Bardzo często trzeba przefiltrować wiersze tabeli przed grupowaniem. Potem zrobić grupowanie na przefiltrowanych danych. A potem odrzucić jakieś niepotrzebne dane już po grupowaniu.

To może po prostu wziąć operator WHERE, skopiować go, nazwać HAVING i wrzucić po GROUP BY?

Tak, dokładnie tak to działa! :)

Różnica między HAVING a WHERE

WHERE filtruje wiersze przed grupowaniem.

Wyobraź sobie, że wybierasz ciasta po smaku: truskawkowe i czekoladowe zostają, reszta odpada. To zadanie dla WHERE.

HAVING filtruje po tym, jak dane zostały pogrupowane i funkcje agregujące zrobiły swoje czary-mary.

Na przykład już pogrupowałeś ciasta po stołach, policzyłeś ich ilość i teraz chcesz zostawić tylko te stoły, gdzie ciast jest więcej niż trzy.

Czyli HAVING używasz do filtrowania danych na poziomie grup.

Składnia HAVING

Składnia jest prawie taka sama jak w WHERE, ale działa trochę inaczej:

SELECT kolumny, funkcje_agregujące
FROM tabela
GROUP BY kolumny
HAVING warunek;

Etapy wykonania:

  1. Najpierw wiersze są filtrowane przez WHERE.
  2. Potem dane są grupowane przez GROUP BY.
  3. Do wyników grupowania stosowane są funkcje agregujące.
  4. Na końcu wynik jest filtrowany przez HAVING.

Przykłady użycia HAVING

Przykład 1: Filtrowanie wydziałów z dużą liczbą studentów

Chcesz się dowiedzieć, które wydziały na uniwerku mają ponad 100 studentów. Załóżmy, że mamy tabelę students:

id name faculty
1 Alice Engineering
2 Bob Engineering
3 Charlie Arts
4 Daisy Business
5 ... ...

Zapytanie:

SELECT faculty, COUNT(*) AS student_count
FROM students
GROUP BY faculty
HAVING COUNT(*) > 100;

Co tu się dzieje:

  • Najpierw grupujemy studentów po kolumnie faculty przez GROUP BY.
  • Potem funkcja agregująca COUNT(*) liczy ilu studentów jest na każdym wydziale.
  • Na końcu HAVING odrzuca wszystkie wydziały, gdzie studentów jest 100 lub mniej.

Wynik:

faculty student_count
Engineering 150
Arts 120

Przykład 2: Działy z wysoką średnią pensją

Chcesz znaleźć tylko te działy, gdzie średnia pensja pracowników przekracza 50 000. Załóżmy, że mamy tabelę employees:

id name department salary
1 Alice IT 60000
2 Bob HR 45000
3 Charlie IT 70000
4 Daisy HR 52000
5 ... ... ...

Zapytanie:

SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;

Wynik:

department avg_salary
IT 65000

Pamiętaj: HAVING działa na wynikach, które zostały policzone po GROUP BY.

Kolejność wykonywania WHERE, GROUP BY i HAVING

Filtrowanie przez WHERE i HAVING odbywa się na różnych etapach. Żeby lepiej to ogarnąć, zobacz krok po kroku jak działa zapytanie:

  1. WHERE: filtrowanie wierszy.

    Na tym etapie przetwarzane są wszystkie wiersze tabeli. Jeśli wiersz nie przejdzie warunku WHERE, nie idzie dalej.

  2. GROUP BY: grupowanie wierszy.

    Po filtrowaniu wiersze są łączone w grupy na podstawie kolumn z GROUP BY.

  3. Funkcje agregujące:

    Do pogrupowanych danych stosowane są funkcje agregujące, jak COUNT(), AVG(), SUM() itd.

  4. HAVING: filtrowanie grup.

    Na tym etapie przetwarzane są tylko wyniki agregatów. Warunki HAVING dotyczą tylko grup.

Specyfika działania HAVING

Specyfika 1: Praca z agregatami

Najważniejsza różnica HAVING od WHERE — to praca z funkcjami agregującymi. Na przykład:

SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;

W tym zapytaniu AVG(salary) nie da się użyć w WHERE, bo WHERE działa na wierszach przed grupowaniem. Zapytanie typu:

SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;

wywali błąd: aggregate functions are not allowed in WHERE.

Specyfika 2: Filtrowanie bez grupowania

Możesz użyć HAVING nawet bez jawnego GROUP BY. Wtedy zapytanie traktuje wszystko jak jedną grupę — wszystkie rekordy:

SELECT AVG(salary) AS avg_salary
FROM employees
HAVING AVG(salary) > 50000;

Praktyczny przykład

Załóżmy, że mamy sklep i tabelę sprzedaży sales:

id product_id sales_amount
1 101 200.00
2 102 300.00
3 101 400.00
4 103 150.00

Zapytanie: znajdź produkty z łączną sprzedażą powyżej 500.

SELECT product_id, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY product_id
HAVING SUM(sales_amount) > 500;

Wynik:

product_id total_sales
101 600.00

Typowe błędy

Użycie agregatów w WHERE:

Na przykład:

SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;

Błąd: funkcji agregujących nie można używać w WHERE.

Błędy z NULL:

Jeśli dane zawierają NULL, filtrowanie może dać nieoczekiwane wyniki. Na przykład:

SELECT department, SUM(salary)
FROM employees
GROUP BY department
HAVING SUM(salary) > 0;

Jeśli kolumna salary zawiera tylko NULL, wynik może być zerowy albo pusty.

Gratulacje. Na tym etapie możesz już śmiało filtrować dane zagregowane! Pamiętaj, że HAVING to Twój klucz do analityki na poziomie grup, gdzie zwykłe WHERE już nie wystarcza.

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION