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
dzień dobry
proszę o pomoc przy zapytaniu SQL w kwerendzie ACCESS
mam tabelę gdzie zapisywane są daty przeglądów urządzeń, każde urządzenie posiada swój numer unikatowy. Mam już kwerendę która wyszukuje daty przeglądów od których do dziś upłynęło powyżej 700dni
SELECT przegl_test.nr_unikatowy, przegl_test.serwisant, przegl_test.data_ost_przegl
FROM przegl_test
WHERE (((przegl_test.data_ost_przegl) Between Date()-700 And Date()-12000));
ps. wpisałem 12000 dni, ponieważ nie wiem co wpisać by wyszukiwało od najstarszej daty
ale to jest kosmetyka, zależy mi na wybraniu z wyszukanych rekordów zawierających po kilka dat przeglądów każdego urządzenia, tylko tych których data jest „najnowsza” po prostu z datą ostatniego przeglądu, klauzulą HAVING.
Hej Roman,
Czemu nie użyjesz po prostu
ORDER BY przegl_test.data_ost_przegl
Nie w tym rzecz, wklejam fragment tabeli dla przykładu
chciałbym taką formułę, która z z tej tabeli w kwenendzie wybierze każdemu „nr_unikatowy” najnowszą „data-ost_przegl”
nr_unikatowy serw data_ost_przegl NIP
EAH1901348884 MD 2021.11.25 5921363645
EAC1901223755 MD 2022.11.24 5921064730
EAC1901223755 MD 2021.11.24 5921575353
EAC1901224800 RK 2021.11.24 5921064730
EAO1901583396 MD 2021.11.23 5922265005
EAO1901582892 RK 2021.11.23 5922265005
EAA1901175476 MD 2021.11.23 5921474770
EAA1901175476 MD 2020.11.22 5921243266
EAA1901171559 RK 2021.11.22 5921559644
czyli z powyższej tabeli powinno zostać tylko po 1 wystąpieniu nr_unikatowy
z najnowszą datą
nr_unikatowy serw data_ost_przegl NIP
EAH1901348884 MD 2021.11.25 5921363645
EAC1901223755 MD 2022.11.24 5921064730
EAC1901224800 RK 2021.11.24 5921064730
EAO1901583396 MD 2021.11.23 5922265005
EAO1901582892 RK 2021.11.23 5922265005
EAA1901175476 MD 2021.11.23 5921474770
EAA1901171559 RK 2021.11.22 5921559644
Cześć jeszcze raz!
Z tego co rozumiem, to musisz zrobić
GROUP BY
ponr_unikatowy
,HAVING
podata_ost_przegl
orazLIMIT 1
Łukasz Dudziński
dziękuję, ale spasowałem, nigdy nie miałem do czynienia z sql i ciągle wyskakują komunikaty o błędzie.