Lekcja 7. Funkcje agregujące i grupowanie danych (GROUP BY)
ŚredniPo co się tego uczymy?
Panel administracyjny sklepu, który pokazuje "liczbę zamówień dzisiaj", "średnią wartość koszyka" albo "najlepiej sprzedający się produkt" — wszystkie te liczby powstają dzięki funkcjom agregującym. Bez nich musiałbyś pobrać tysiące wierszy i liczyć to ręcznie w aplikacji.
Teoria
Czasem nie interesuje Cię każdy wiersz z osobna, tylko PODSUMOWANIE całego zbioru — ile mamy klientów, jaka jest średnia cena, który produkt jest najdroższy. Do takich obliczeń służą funkcje agregujące.
Funkcja / Działanie:
COUNT() — liczy wiersze.
SUM() — liczy sumę.
AVG() — liczy średnią.
MAX() — zwraca największą wartość.
MIN() — zwraca najmniejszą wartość.
Przykłady:
SELECT COUNT(*) AS liczba_klientow FROM Klienci;
SELECT AVG(cena) AS srednia_cena FROM Produkty;
SELECT MAX(cena) AS najdrozszy FROM Produkty;
Funkcje agregujące same w sobie liczą jedną wartość dla CAŁEJ tabeli. Żeby policzyć np. sumę osobno DLA KAŻDEJ kategorii produktów, potrzebujesz GROUP BY:
SELECT kategoria, COUNT(*) AS ile, AVG(cena) AS srednia
FROM Produkty
GROUP BY kategoria;
To zapytanie podzieli produkty na grupy według kategorii, a potem policzy COUNT i AVG OSOBNO dla każdej grupy.
Jeśli chcesz jeszcze przefiltrować WYNIKI grupowania (np. pokazać tylko kategorie z więcej niż 5 produktami), używasz HAVING — to jest "WHERE dla grup", bo zwykłego WHERE nie można użyć z funkcją agregującą:
SELECT kategoria, COUNT(*) AS ile
FROM Produkty
GROUP BY kategoria
HAVING COUNT(*) > 5;
Przykład z życia
Wyobraź sobie listę wszystkich zamówień w sklepie muzycznym — setki wierszy. Zamiast przeglądać je jeden po drugim, pytasz bazę wprost: "ile mamy klientów", "jaka jest średnia wartość zamówienia", "który produkt jest najdroższy" — i dostajesz gotową liczbę.
Kod (SQL)
-- ile produktów jest w każdej kategorii i jaka jest ich średnia cena
SELECT kategoria, COUNT(*) AS liczba_produktow, AVG(cena) AS srednia_cena
FROM Produkty
GROUP BY kategoria;
-- tylko kategorie, w których jest więcej niż 2 produkty
SELECT kategoria, COUNT(*) AS liczba_produktow
FROM Produkty
GROUP BY kategoria
HAVING COUNT(*) > 2;
-- łączna wartość zamówień każdego klienta (agregacja po JOIN-ie)
SELECT Klienci.imie, Klienci.nazwisko, SUM(Zamowienia.ilosc * Produkty.cena) AS suma_wydana
FROM Zamowienia
JOIN Klienci ON Zamowienia.id_klienta = Klienci.id_klienta
JOIN Produkty ON Zamowienia.id_produktu = Produkty.id_produktu
GROUP BY Klienci.id_klienta;
Komentarz i wyjaśnienie kodu
Pierwsze zapytanie grupuje produkty po kolumnie kategoria i dla każdej grupy liczy dwie rzeczy naraz: COUNT (ile produktów) i AVG (jaka średnia cena). Drugie zapytanie robi to samo, ale dokłada HAVING, żeby odfiltrować grupy z małą liczbą produktów — to different od WHERE, bo HAVING działa PO grupowaniu, na już policzonych wynikach. Trzecie zapytanie łączy JOIN z GROUP BY: najpierw łączymy trzy tabele, a dopiero potem grupujemy po kliencie i sumujemy wartość jego zamówień.
Ćwiczenie samodzielne
Napisz zapytanie, które pokaże, ile zamówień złożył każdy klient (GROUP BY po kliencie, COUNT zamówień).
Zadania do pracy własnej
Zadanie 1. GROUP BY w sklepie muzycznym
Uwaga przed importem: plik z bazą jest spakowany jako
.gz. phpMyAdmin w XAMPP przyjmuje takie pliki bez rozpakowywania. Jeżeli po pobraniu nazwa wygląda np.sklep_muzyczny.sql_.gzi import nie przejdzie, zmień nazwę pliku nasklep_muzyczny.sql.gz, a potem wybierz go w zakładce Importuj.Baza do pracy: Sklep muzyczny (.sql.gz). Zaimportuj spakowany plik SQL w XAMPP/phpMyAdmin, a następnie wykonaj zapytania.
- Policz liczbę wszystkich klientów.
- Policz ilu klientów pochodzi z każdego miasta.
- Oblicz średnią cenę produktów w każdej kategorii.
- Oblicz łączną wartość wszystkich zamówień.
- Oblicz sumę zamówień dla każdego klienta.
- Policz liczbę zamówień dla każdego klienta.
- Pokaż kategorie, których średnia cena przekracza 200 zł.
- Pokaż trzy produkty o największej łącznej liczbie zamówionych sztuk.
- Oblicz wartość sprzedaży dla każdego dnia.
- Pokaż klientów, których suma zamówień przekracza 1000 zł.
Zadanie 2. GROUP BY w bibliotece szkolnej
Uwaga przed importem: plik z bazą jest spakowany jako
.gz. phpMyAdmin w XAMPP przyjmuje takie pliki bez rozpakowywania. Jeżeli po pobraniu nazwa wygląda np.sklep_muzyczny.sql_.gzi import nie przejdzie, zmień nazwę pliku nasklep_muzyczny.sql.gz, a potem wybierz go w zakładce Importuj.Baza do pracy: Biblioteka szkolna (.sql.gz). Zaimportuj spakowany plik SQL w XAMPP/phpMyAdmin, a następnie wykonaj zapytania.
- Policz wszystkie książki w tabeli.
- Policz liczbę książek w każdym gatunku.
- Oblicz średnią liczbę stron według autorów.
- Wyświetl najstarszą i najnowszą książkę w każdym gatunku.
- Policz liczbę książek wydanych w każdym roku.
- Wyświetl autorów, którzy mają więcej niż jedną książkę.
- Oblicz średnią liczbę stron dla każdego gatunku i posortuj malejąco.
- Wyświetl gatunki, w których średnia liczba stron przekracza 350.
- Znajdź najdłuższą książkę każdego autora.
- Policz książki wydane przed 1900 i od 1900 roku, używając CASE.
Zadanie 3. GROUP BY w aptece i magazynie
Uwaga przed importem: plik z bazą jest spakowany jako
.gz. phpMyAdmin w XAMPP przyjmuje takie pliki bez rozpakowywania. Jeżeli po pobraniu nazwa wygląda np.sklep_muzyczny.sql_.gzi import nie przejdzie, zmień nazwę pliku nasklep_muzyczny.sql.gz, a potem wybierz go w zakładce Importuj.Baza do pracy: Apteka Zdrowie (.sql.gz). Zaimportuj spakowany plik SQL w XAMPP/phpMyAdmin, a następnie wykonaj zapytania.
- Wyświetl wszystkie leki wraz z kategorią i producentem.
- Wyświetl leki, których stan magazynowy jest mniejszy niż 50.
- Policz liczbę leków w każdej kategorii.
- Oblicz średnią cenę leków według kategorii.
- Oblicz wartość magazynu każdego leku: cena * ilość_magazyn.
- Pokaż trzy najdroższe leki.
- Wyświetl sprzedaż: nazwa leku, ilość, data, wartość sprzedaży.
- Oblicz sumę sprzedanych sztuk dla każdego leku.
- Pokaż producentów, których leki były sprzedawane.
- Pokaż kategorie, w których średnia cena przekracza 20 zł.
Typowe błędy
Najczęstszy błąd to umieszczenie w SELECT kolumny, po której NIE grupujemy i która nie jest objęta funkcją agregującą — SQL zgłosi błąd albo (w niektórych bazach) zwróci przypadkową wartość. Drugi błąd: próba użycia funkcji agregującej w WHERE zamiast w HAVING (WHERE działa przed grupowaniem i nie "widzi" jeszcze wyników agregacji). Trzeci: mylenie COUNT(*) (liczy wszystkie wiersze) z COUNT(kolumna) (liczy tylko wiersze, gdzie ta kolumna nie jest NULL).
Nawiązanie do egzaminu zawodowego
Funkcje agregujące i grupowanie to jeden z typowych elementów efektu "wyszukuje informacje w bazie danych przy użyciu języka SQL" — zadania praktyczne w INF.03 często wymagają policzenia sum, średnich albo zestawień pogrupowanych po kategorii czy dacie.