CodeGym /Kursy /SQL SELF /Porównanie WHERE i HAVING: analiza kolejności wykonywania...

Porównanie WHERE i HAVING: analiza kolejności wykonywania i przykłady

SQL SELF
Poziom 8 , Lekcja 2
Dostępny

Przejdźmy jeszcze raz przez kolejność wykonywania operacji w SQL, a także przez to, z czym może i nie może pracować WHERE i HAVING. To ważny temat, na którym opiera się wiele niuansów działania zapytań SQL. Musisz to naprawdę dobrze ogarnąć.

To czym właściwie WHERE różni się od HAVING, kiedy używać jednego, a kiedy drugiego i jak one się ze sobą łączą? To pomoże Ci nie pogubić się w logice zapytań i skutecznie filtrować dane. Podsumujmy naszą wiedzę o WHERE i HAVING.

Czym jest WHERE?

WHERE — to warunek, który służy do filtrowania wierszy przed grupowaniem lub użyciem funkcji agregujących. Czyli najpierw z tabeli wybierane są wiersze spełniające kryteria, a dopiero potem na tych danych robimy grupowanie.

👉 Wyobraź sobie, że zbierasz owoce na targu. WHERE — to filtr, który pozwala Ci od razu odrzucić zgniłe jabłka, zanim zaczniesz je sortować według rozmiaru czy koloru.

Przykład:

SELECT *
FROM students
WHERE age > 18;

To zapytanie wybierze wszystkich studentów starszych niż 18 lat przed wykonaniem jakichkolwiek innych operacji.

Czym jest HAVING?

HAVING — to filtr, który stosujemy po zgrupowaniu danych (GROUP BY). Pozwala nakładać warunki na zgrupowane dane, np. zostawić tylko te grupy, gdzie średnia ocen studentów jest wyższa niż 80.

👉 Wracając do przykładu z jabłkami. HAVING — to filtr, którego używasz już po posortowaniu jabłek do koszyków (grup). Teraz interesują Cię np. tylko te koszyki (grupy), gdzie jest więcej niż dziesięć jabłek.

Przykład:

SELECT koszyk, COUNT(*)
FROM jablka
GROUP BY koszyk
HAVING COUNT(*) > 10;

To zapytanie wybierze tylko te koszyki, gdzie liczba jabłek jest większa niż 10.

Główne różnice:

Cecha WHERE HAVING
Zastosowanie Filtruje wiersze przed grupowaniem Filtruje grupy po grupowaniu
Praca z agregacją Nie można używać funkcji agregujących Można używać funkcji agregujących
Cel Usuwa zbędne wiersze do grupowania Usuwa grupy, które nie spełniają warunku

Kolejność wykonywania WHERE, GROUP BY i HAVING

Żeby lepiej zrozumieć, jak działają WHERE i HAVING, zobaczmy na kolejność wykonywania zapytań SQL:

  1. Najpierw wykonuje się FROM, wybierane są wiersze z tabeli.
  2. Potem stosowany jest WHERE, filtrowane są tylko te wiersze, które spełniają warunki.
  3. Później następuje grupowanie przez GROUP BY. Dostajemy nową tabelę z danymi grup.
  4. Stosowany jest HAVING, filtrowane są grupy, które spełniają warunki.
  5. Na końcu wybierane są wyniki SELECT.

Schematycznie wygląda to tak:

1. FROM → 2. WHERE → 3. GROUP BY → 4. HAVING → 5. SELECT

Przykład:

SELECT department, AVG(age) AS avg_age
FROM students
WHERE age > 18
GROUP BY department
HAVING AVG(age) > 20;

Co się tutaj dzieje:

  1. W tabeli students wybierane są wiersze, gdzie age > 18 (używany jest WHERE).
  2. Pozostałe wiersze są grupowane według department.
  3. Dla każdej grupy liczony jest średni wiek studentów.
  4. Grupy, gdzie średni wiek jest mniejszy lub równy 20, są odrzucane przez HAVING.
  5. Wyniki są wyświetlane.

Przykłady łączonego użycia

Przykład 1: Filtrowanie przed i po grupowaniu

Warunek: znaleźć wydziały, gdzie jest więcej niż 5 studentów, biorąc pod uwagę tylko studentów starszych niż 18 lat.

Wyjściowa tabela students

id name department age gpa
1 Alex Lin ComputerSci 20 3.8
2 Maria Chi Math 22 3.5
3 Anna Song ComputerSci 19 4.0
4 Otto Art Math 17 3.9
5 Liam Park Physics 21 3.7
6 Jane Doe ComputerSci 23 3.6
7 Tom Brown Math 25 3.4
8 Sara White Math 19 3.8
9 John Smith ComputerSci 20 3.7
10 Emily Green Physics 18 3.9
11 Mark Blue ComputerSci 21 3.5
12 Zoe Black Math 22 3.6
13 Max Gray ComputerSci 20 3.9
14 Eva Gold Math 23 3.7
15 Nick Silver Physics 19 3.8

Zapytanie:

SELECT department, COUNT(*) AS student_count
FROM students
WHERE age > 18
GROUP BY department
HAVING COUNT(*) > 5;

Wynik: -- Wynik zapytania

department student_count
ComputerSci 6

Wyjaśnienie:

  1. Najpierw usuwamy wiersze, gdzie age <= 18 (warunek WHERE).
  2. Grupujemy dane według wydziałów (GROUP BY department).
  3. Liczymy liczbę studentów w każdej grupie.
  4. Odrzucamy grupy, gdzie studentów jest mniej lub równo 5 (HAVING COUNT(*) > 5).

Przykład 2: Błąd przy użyciu WHERE zamiast HAVING

Warunek: Znaleźć wydziały, gdzie średni wiek jest większy niż 22 lata.

Niepoprawne zapytanie:

SELECT department, AVG(age) AS avg_age
FROM students
WHERE AVG(age) > 22
GROUP BY department;

Błąd: SQL nie pozwala używać funkcji agregujących AVG w WHERE, bo na tym etapie agregaty jeszcze nie są policzone.

Poprawne zapytanie:

SELECT department, AVG(age) AS avg_age
FROM students
GROUP BY department
HAVING AVG(age) > 22;

Tutaj warunek AVG(age) > 22 stosowany jest po grupowaniu.

Praktyczne wskazówki

Jeśli musisz filtrować wiersze, używaj WHERE. Przykład: Znaleźć wszystkich pracowników z pensją powyżej 5000.

SELECT *
FROM employees
WHERE salary > 5000;

Jeśli musisz filtrować grupy, używaj HAVING. Przykład: Znaleźć działy z łączną pensją powyżej 100 000.

SELECT department, SUM(salary) AS total_salary
FROM employees
GROUP BY department
HAVING SUM(salary) > 100000;

Łącz WHERE i HAVING dla bardziej złożonych warunków.

Przykład: Znaleźć kraje z liczbą mieszkańców powyżej 10 milionów, biorąc pod uwagę tylko miasta, gdzie populacja jest większa niż 1 milion.

SELECT country, SUM(population) AS total_population
FROM cities
WHERE population > 1000000
GROUP BY country
HAVING SUM(population) > 10000000;

Typowe błędy i jak ich unikać

Jednym z najczęstszych błędów jest mylenie WHERE i HAVING. Na przykład próba użycia funkcji agregującej w WHERE:

SELECT department, COUNT(*)
FROM students
WHERE COUNT(*) > 10
GROUP BY department;

Takie zapytanie zwróci błąd, bo obliczenia agregujące nie są dostępne na etapie WHERE. Poprawne podejście — użyć HAVING:

SELECT department, COUNT(*)
FROM students
GROUP BY department
HAVING COUNT(*) > 10;

Kolejny błąd to wybór złych warunków do WHERE. Na przykład:

SELECT department, AVG(age) AS avg_age
FROM students
WHERE avg_age > 20
GROUP BY department;

Tutaj warunek avg_age > 20 jest niepoprawny, bo avg_age jeszcze nie jest policzony. Rozwiązanie — przenieść ten warunek do HAVING:

SELECT department, AVG(age) AS avg_age
FROM students
GROUP BY department
HAVING AVG(age) > 20;

Mam nadzieję, że teraz masz jasność, czym różnią się WHERE i HAVING, jak ich poprawnie używać i jak unikać typowych błędów. Ta wiedza przyda Ci się przy tworzeniu złożonych raportów, filtrowaniu danych do analizy i optymalizacji zapytań. Czyli do większości prawdziwych zapytań SQL, które będziesz pisać :)

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