Informacje o nowych artykułach oraz akcjach edukacyjnych prosto na Twojej skrzynce e-mail!

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ącychfunkcji 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:

IDImieNazwiskoMiasto
1JanKowalskiWarszawa
2MichałŁagodaKraków
3MarcinKulczykKraków
4RadosławSikorskiKraków
5MonikaKopaczGdańsk
6PiotrGrabiecToruń
7EwaPogodnaBydgoszcz
8SebastianSzybkiWarszawa

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:

ImieNazwiskoMiasto
RadosławSikorskiKrakó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.

Spodobało się?

Jeśli tak, to zarejestruj się do newslettera aby otrzymywać informacje nowych artykułach oraz akcjach edukacyjnych. Gwarantuję 100% satysfakcji i żadnego spamowania!

, , , , ,

Dodaj komentarz

Komentarze (10)

  • Kordian Bober pisze:

    dobry artykuł. Przystępnie opisane

  • Radziwil pisze:

    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

      • Radziwil pisze:

        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

  • Roman Grajoszek pisze:

    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

      • Roman Grajoszek pisze:

        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 po nr_unikatowy, HAVING po data_ost_przegl oraz LIMIT 1

        Łukasz Dudziński

  • Roman Grajoszek pisze:

    dziękuję, ale spasowałem, nigdy nie miałem do czynienia z sql i ciągle wyskakują komunikaty o błędzie.

Odpowiedz

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

Pin It on Pinterest