Odczytywanie danych z bazy – select group by, having

Group by:

Bardzo często zachodzi potrzeba zgrupowania danych oraz wyciągnięcia z nich jakiś informacji, np ilości rekordów, wartości średniej, minimalnej itp. Podczas pisania kwerendy select można zlecić silnikowi bazy zgrupowania danych. Służy do tego operator group by. Aby wyciągnąć informacje z zgrupowanych danych, trzeba użyć funkcji agregujących. Podstawowe funkcje agregujące opisałem tutaj.

Podstawowa forma użycia operatora group by:

select pola from tabela group by pola_grupowania

Pola_grupowania służą do zdefiniowania, według których silnik bazy danych ma przeprowadzić grupowanie danych. Te pola mogą zostać zwrócone bezpośrednio przez kwerendę. Inne pola, po których grupowanie nie jest przeprowadzane, muszą być zwrócone poprzez funkcje agregujące.

Having:

Warunek where jest stosowany przez silnik bazy danych do poszczególnych rekordów. Niektóre sytuacje wymagają, aby wykonać operacje na zbiorach danych poprzez funkcje agregujące, wyciągając informacje analityczne dla jakiegoś przypadku.

Klauzura having pozwala wykonać warunek na zbiorach z użyciem funkcji agregujących, jest wykorzystywana razem z group by.

Zasada użycia having:

select pola from tabela group by pola_grupowania having warunek

Warunek zostanie zastosowany do pogrupowanych zbiorów danych.

Przykłady:

W przykładnie dla ułatwienia będę korzystał z widoku vuser_history_data. Zakładam zwracanie następujących danych:

Dane wykorzystywane w przykładzie: widok vuser_history_data

Group by:

Przykład 1:

Zgrupujmy dane po user_name i wyświetlmy ilość rekordów, możemy do tego wykorzystać następujący kod:

select user_name, count(dt) as count_dt, count(book_name) as count_book_name, count(distinct book_name) as unique_book_name
from vuser_history_data
group by user_name

Dla danego przykładu zostaną zwrócone następujące dane:

Wynik kwerendy:
select user_name, count(dt) as count_dt, count(book_name) as count_book_name, count(distinct book_name) as unique_book_name
from vuser_history_data
group by user_name

Otrzymane wyniki wymagają następującego komentarza:

Dla danych zgrupowanych po user_name count(dt) as count_dt zliczyło wszystkie wartości dt. Count(book_name) as count_book_name zwróciło inne wartości niż dla dt, ponieważ niektóre pozycje mają wartość null i zostały pominięte. Count(distinct book_name) as unique_book_name przed zliczeniem wyeliminował duplikaty.

Przykład 2:

Sprawdźmy osoby, które dostały upomnienia. Uzyskajmy informacje: kto, datę pierwszego upomnienia oraz ilość upomnień:

select user_name, min(dt) as dt, count(dt) as count from vuser_history_data
where descr = 'Upomnienie'
group by user_name

Uzyskamy następujące wyniki:

Wynik powyższego zapytania:
select user_name, min(dt) as dt, count(dt) as count from vuser_history_data
where descr = 'Upomnienie’
group by user_name
Przykład 3:

Grupować możemy po wielu kolumnach:

select user_name, descr
from vuser_history_data
group by user_name, descr

Otrzymamy wyniki:

Rezultat zapytania:
select user_name, descr
from vuser_history_data
group by user_name, descr
Ciekawostka:

Można zliczać po kolumnie, po której grupujemy:

select user_name, count(user_name)
from vuser_history_data
group by user_name
Wynik działania kwerendy:
select user_name, count(user_name)
from vuser_history_data
group by user_name

Ponieważ cały czas mamy wszystkie rekordy zwracane przez widok, ale silnik bazy danych dokonał ich podzielenia według user_name.

Having:

Przykład 1:

Do kodu z przykładu 2 z użycia group by dodajmy klauzurę having, której zadaniem będzie zwrócenie użytkowników, których minimalna data będzie większa lub równa 2020-06-27:

select user_name, min(dt) as dt, count(dt) as count from vuser_history_data
where descr = 'Upomnienie'
group by user_name
having min(dt) >= '20200627'

Otrzymamy:

Wyniki zwrócone poprzez powyższe zapytanie.
Przykład 2:

Jeśli potrzebujemy wyświetlić rekordy, dla których ostatnia data jest większa lub równa 2020-06-27 to możemy użyć następującego kodu:

select user_name, max(dt) as dt, count(dt) as count from vuser_history_data
group by user_name
having max(dt) >= '20200627'

Jako rezultat zobaczymy:

Rezultat:
select user_name, max(dt) as dt, count(dt) as count from vuser_history_data
group by user_name
having max(dt) >= '20200627′

Podsumowanie:

Jednym z głównych elementów do których są wykorzystywane gropy by oraz having są raporty oraz wszelkiego rodzaju dane analityczne. Służą do uzyskania danych, które da się pogrupować w zbiory.

Aby wyciągnąć konkretne informacje należy wykorzystać funkcje agregujące. Pozwalają na wykonanie obliczeń typu min, max, oraz innych.

Having pełni rolę operacji where na zgrupowanych danych. Jest wykonywany po pogrupowaniu danych. Operator where działa dla poszczególnych rekordów, a having dla zbiorów.

Dodaj komentarz

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