HAVING – filtrowanie grup

Jest to trzeci i ostatni krok, w którym możemy filtrować elementy zbioru wynikowego. Różni się zasadniczo od poznanych do tej pory, związanych z selekcją wierszy we FROM (gdzie filtrem są warunki złączeń z innymi tabelami) oraz WHERE.

(5)     SELECT
(1)	FROM
(2)	WHERE
(3)	GROUP BY
(4)     HAVING
(6)     ORDER BY

Operacja grupowania opisana w artykule na temat GROUP BY, wprowadza pewne ograniczenia. W każdym kolejnym kroku po GROUP BY, odwoływać się możemy bezpośrednio tylko do atrybutów (kolumn) sekcji grupującej. Do pozostałych kolumn (sekcji danych surowych) tylko za pośrednictwem funkcji agregujących.

HAVING jest kolejnym krokiem po GROUP BY – działamy zatem na całych grupach wierszy. Jest to tak zwana selekcja pozioma grup wierszy. Warunki określone w WHERE, traktujemy jako selekcję poziomą pojedynczych rekordów.


Sposób działania HAVING w SQL

Najlepiej pokazać to na przykładzie. W naszym scenariuszu, będziemy działać na bazie Northwind. Załóżmy że potrzebujemy wyciągnąć informacje o miastach w Brazylii, w których mamy więcej niż jednego Klienta (z tabeli dbo.Customers).

Pierwszym krokiem, będzie selekcja pozioma wierszy (WHERE) do odfiltrowania wszystkich Klientów z Brazylii. Działanie tego filtra jest proste, wybieramy precyzyjnie tylko te pojedyncze rekordy, których Country = ’Brazil’. Fragment działania filtra w WHERE obrazuje poniższy zrzut :
Having_01
Otrzymamy wyselekcjonowane wiersze zgodnie z definicją filtra w WHERE.

select Country, CIty, CustomerID , ContactName, CompanyName  
from dbo.Customers
WHERE Country = 'Brazil'

Having_02
Kolejnym krokiem analizy naszych danych, niech będzie wyciągnięcie informacji o liczbie Klientów z danego miasta w Brazylii.

select CIty, COUNT(CustomerID) as CustQty
from dbo.Customers
WHERE Country = 'Brazil'
GROUP BY City

Having_03
Filtrowanie w HAVING, polega na filtrowaniu całych grup rekordów. Zgodnie z zasadą opisaną na początku artykułu, możemy filtrować po kolumnach grupujących lub pozostałych, za pośrednictwem funkcji agregujących. W tym momencie, chcemy właśnie filtrować grupy rekordów, ze względu na ilość elementów (liczby klientów) w ich ramach.

Cel ten zrealizuje filtrowanie za pomocą HAVING. Filtrem będzie wynik funkcją agregującej COUNT(), wybierający tylko te grupy, dla których ilość wierszy (Klientów) będzie większa od 1.

select City, COUNT(CustomerID) as CustQty
from dbo.Customers
WHERE Country = 'Brazil'
GROUP BY City
HAVING COUNT(CustomerID)>1

Having_04
Tworzenia filtrów w HAVING podobnie jak w WHERE, umożliwia łączenie wielu warunków ze sobą, za pomocą operatorów logicznych AND i OR. Powyższe zapytanie, moglibyśmy również zapisać w ten sposób :

select Country,City, COUNT(CustomerID) as CustQty
from dbo.Customers
GROUP BY Country, City
HAVING Country = 'Brazil' AND COUNT(CustomerID) >1

Wynik działania będzie identyczny. Zauważ jednak, że istnieje różnica logiczna w jego przetworzeniu. Przynajmniej teoretycznie, w tym przypadku, całość filtracji odbędzie się tylko w kroku HAVING.
W praktyce optymalizator i tak zastosuje filtrację w pierwszym kroku przetwarzania, minimalizując liczbę rekordów, które będzie przetwarzał w kolejnych etapach. Zobaczyć można to na planie wykonania. Obydwa zapytania posiadają identyczny plan.
Having_06
Having_05


Podsumowanie

Ważne jest abyś dobrze zrozumiał, w jaki sposób wykonywane są zapytania. Pozwala to zapobiec popełnianiu, najtrudniej wykrywalnych błędów logicznych.

Pamiętać należy również, że funkcje agregujące pomijają w kalkulacjach wartości null. Więcej na temat grupowania, having oraz stosowania funkcji agregujacych znajdziesz w rozdziale opisującym szerzej, praktyczne aspekty pisania zapytań.

One Response

  • Przede wszystkim dziękuję za świetny kurs.

    Myślę, że do sekcji o HAVING można by dodać jeszcze to, co napisano tutaj , otóż, że „The HAVING clause was added to SQL because the WHERE keyword could not be used with aggregate functions”. Mnie to bardzo pomogło intuicyjnie zrozumieć istotę działania HAVING.

    Pozdawiam

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.