Grupowanie danych: Klauzula HAVING w SQL cz. IV
Klauzula HAVING
w SQL według ogólnego wzoru zapytań SELECT
podanego w artykule „Podstawowa wersja zapytania SELECT w SQL (SELECT … FROM … WHERE …)” wykonywana jest po klauzuli GROUP BY, czyli po pogrupowaniu danych. Działa ona w zasadzie tak samo jak słowo kluczowe WHERE, z takim wyjątkiem, że przy WHERE
nie mogliśmy używać funkcji grupujących, funkcji rankingu oraz operować na pogrupowanych danych. W klauzuli HAVING
jest to wszystko dopuszczalne. W skrócie funkcja ta może zostać wykorzystana na przykład do wyeliminowania grup danych, które nie spełniają podanego po niej warunku logicznego.
Ogólna składnia zapytania SELECT
zawierającego klauzulę HAVING
:
SELECT kolumna1, kolumna2 FROM tabela GROUP BY kolumna3 HAVING kolumna4 > 10; --warunek logiczny
Tabela klienci
na której będziemy uruchamiać przykładowe zapytania:
ID | Imie | Nazwisko | Miasto |
1 | Jan | Kowalski | Warszawa |
2 | Michał | Łagoda | Kraków |
3 | Marcin | Kulczyk | Kraków |
4 | Radosław | Sikorski | Kraków |
5 | Monika | Kopacz | Gdańsk |
6 | Piotr | Grabiec | Toruń |
7 | Ewa | Pogodna | Bydgoszcz |
8 | Sebastian | Szybki | Warszawa |
Pobierzmy z tabeli klienci
miasta z których mamy przynajmniej dwóch klientów:
SELECT Miasto FROM klienci GROUP BY Miasto HAVING COUNT(*) > 1;
Efekt:
Miasto |
Kraków |
Warszawa |
A teraz wykonajmy to samo zapytanie tylko zamiast HAVING
użyjmy WHERE
:
SELECT miasto FROM klienci WHERE COUNT(*) > 1 -- BŁĄD!!! GROUP BY miasto;
Oczywiście otrzymaliśmy błąd, gdyż jak wspomniałem na początku w klauzuli WHERE
nie można używać funkcji grupujących i rankingowych.
Pobierzmy informacje o miastach w których mamy klienta o imieniu „Radosław”:
SELECT imie, nazwisko, miasto FROM klienci GROUP BY miasto HAVING imie = 'Radosław';
Efekt:
Imie | Nazwisko | Miasto |
Radosław | Sikorski | Kraków |
Jak można się zorientować przerabiając powyższe przykłady, dane w naszym zapytaniu są najpierw grupowane, a potem wywoływana jest klauzula HAVING
. Gdybyśmy użyli słowo kluczowe WHERE
, to było by dokładnie na odwrót czyli grupowali byśmy tylko przefiltrowane wyniki co w niektórych przypadkach mogło by nam dać złe dane.
dobry artykuł. Przystępnie opisane
Czy możemy wykonać takie zapytanie?
SELECT id
FROM klienci
GROUP BY id
HAVING imie = 'Radosław’;
Hej,
Ale co to miało by robić?
Id
jest unikalne dla każdego rekordu. Po co to grupowanie wtedy?Łukasz Dudziński
Hej
Potrzeba pobrania wszystkich ID, kiedy w kolumna imie = 'Radosław’. Poszukuję rozwiązania dla mojego przypadku, tj. pobrania wszystkich ID (jest to wynik podzapytania), kiedy np. ID pracownika występuje więcej niż jeden raz. Takie zapytanie jest poprawne:
select tab1.idprac, count (tab1.idprac)
from tab1
where tab1.data1 between to_date (’2023-01-01′, 'YYYY-MM-DD’) and to_date (’2023-03-31′, 'YYYY-MM-DD’)
group by tab1.idprac
having count (tab1.idprac) > '1′;
Moją intencją jest uzyskanie takiego wyniku
select tab1.num_ewid, tab1.data1
from tab1
where tab1.id in (
select tab1.id
from tab1
where tab1.data1 between to_date (’2023-01-01′, 'YYYY-MM-DD’) and to_date (’2023-03-31′, 'YYYY-MM-DD’)
group by tab1.idprac
having count (tab1.idprac) > '1′);
Taki zapis jest nie prawidłowy.
Moją potrzebą jest wyświetlić dla kolumn num_ewid oraz data1 wszystkie rekordy, dla których w zadanym przedziale czasu idprac występuje więcej niż jeden raz.
Pozdrawiam
Darek
Cześć Darek,
Jeśli możesz wklej tutaj strukturę tabeli z której chcesz wyciągnąć dane.
Pozdrawiam,
Łukasz Dudziński, autor bloga Strefakodera.pl