Funkcje agregujące, GROUP BY i HAVING

INF.03 · teoria
autor: redakcja · 07.09.2026 · aktualizacja: 08.09.2026
Jak policzyć wiersze, zsumować i uśrednić wartości, jak podzielić tabelę na grupy przez GROUP BY, czym różni się HAVING od WHERE oraz funkcje tekstowe, liczbowe i daty w MySQL. Lekcja 8.5 kursu INF.03.
Funk­cja agre­gu­ją­ca liczy JEDNĄ war­tość z wielu wier­szy: ile ich jest, ile wynosi suma, jaka jest śred­nia. Razem z GROUP BY (GRUPUJ WEDŁUG) po­zwa­la od­po­wie­dzieć na py­ta­nia w ro­dza­ju „ile pro­duk­tów jest w każdej ka­te­go­rii". Na eg­za­mi­nie pi­sem­nym wra­ca­ją dwa tematy z tej lekcji: róż­ni­ca między COUNT(*) a COUNT(kolumna) przy war­to­ściach NULL oraz róż­ni­ca między WHERE a HAVING. In­for­ma­tor CKE wy­mie­nia „wy­ko­rzy­sta­nie funk­cji agre­gu­ją­cych" wprost jako temat za­da­nia prak­tycz­ne­go.

Tabela do przy­kła­dów

[ TABELA PRODUKT ]
id
nazwa
cena
ka­te­go­ria
sztuk
1
Kla­wia­tu­ra
120
ak­ce­so­ria
15
2
Mysz
45
ak­ce­so­ria
0
3
Mo­ni­tor 24
650
mo­ni­to­ry
4
4
Mo­ni­tor 27
990
mo­ni­to­ry
2
5
Kabel HDMI
25
ak­ce­so­ria
NULL

Pięć funk­cji agre­gu­ją­cych

Funk­cja
Znaczy
Za­py­ta­nie
Wynik
COUNT
policz
SELECT COUNT(*) FROM produkt;
5
SUM
suma
SELECT SUM(cena) FROM produkt;
1830
AVG
śred­nia
SELECT AVG(cena) FROM produkt;
366
MIN
naj­mniej­sza
SELECT MIN(cena) FROM produkt;
25
MAX
naj­więk­sza
SELECT MAX(cena) FROM produkt;
990
Bez GROUP BY funk­cja liczy z CAŁEJ tabeli i zwraca jeden wiersz. MIN i MAX dzia­ła­ją też na tek­ście (al­fa­be­tycz­nie) i na datach (naj­wcze­śniej­sza i naj­póź­niej­sza).
Wynik warto nazwać, bo do­myśl­na nazwa ko­lum­ny to całe wy­ra­że­nie:
SELECT COUNT(*) AS ile, AVG(cena) AS srednia FROM produkt;

COUNT(*) kontra COUNT(ko­lum­na)

To jedno z naj­częst­szych pytań o NULL.
Za­py­ta­nie
Wynik
Dla­cze­go
SELECT COUNT(*) FROM produkt;
5
liczy WIERSZE, nie­za­leż­nie od za­war­to­ści
SELECT COUNT(sztuk) FROM produkt;
4
pomija wiersz, w którym sztuk jest NULL
SELECT COUNT(DISTINCT kategoria) FROM produkt;
2
liczy różne war­to­ści: ak­ce­so­ria, mo­ni­to­ry
Po­zo­sta­łe funk­cje też po­mi­ja­ją NULL. Dla­te­go AVG(sztuk) z naszej tabeli to (15 + 0 + 4 + 2) po­dzie­lo­ne przez 4, czyli 5,25, a nie przez 5. Zero jest war­to­ścią i wcho­dzi do ra­chun­ku; NULL nie.
Pu­łap­ka: COUNT(*) liczy wier­sze, COUNT(kolumna) liczy wier­sze z WYPEŁNIONĄ ko­lum­ną. Jeżeli py­ta­nie po­ka­zu­je tabelę z pu­sty­mi polami, te dwie od­po­wie­dzi będą różne i o to wła­śnie chodzi.

GROUP BY: po­dział na grupy

GROUP BY dzieli wier­sze na grupy według war­to­ści ko­lum­ny, a funk­cja agre­gu­ją­ca liczy osobno w każdej grupie.
SELECT kategoria, COUNT(*) AS ile, AVG(cena) AS srednia FROM produkt GROUP BY kategoria;
ka­te­go­ria
ile
sred­nia
ak­ce­so­ria
3
63.33
mo­ni­to­ry
2
820.00
Trzy kroki grupowania: pięć wierszy tabeli, podział na dwie grupy według kategorii, jeden wiersz wyniku na grupę
Zasada, która roz­strzy­ga więk­szość pytań: w SELECT mogą stać tylko ko­lum­ny wy­mie­nio­ne w GROUP BY oraz funk­cje agre­gu­ją­ce. Za­py­ta­nie SELECT nazwa, COUNT(*) FROM produkt GROUP BY kategoria; jest błędne, bo w grupie „ak­ce­so­ria" są trzy różne nazwy i baza nie wie, którą po­ka­zać.
Gru­po­wać można po kilku ko­lum­nach naraz: GROUP BY kategoria, sztuk tworzy grupę dla każdej pary war­to­ści.
W prze­glą­dar­ce usuń GROUP BY i wy­ko­naj za­py­ta­nie po­now­nie, potem dopisz HAVING COUNT(*) >= 3:
[ SQL ]
baza: sklep
zapytanie
98/4000
Otwórz w placu zabaw ›

HAVING kontra WHERE

Oba fil­tru­ją, ale w innym mo­men­cie i na innym po­zio­mie.
SELECT kategoria, COUNT(*) AS ile FROM produkt WHERE cena > 30 -- odrzuca WIERSZE przed grupowaniem GROUP BY kategoria HAVING COUNT(*) >= 2; -- odrzuca GRUPY po policzeniu
Ko­lej­ność wy­ko­na­nia w bazie: FROM, WHERE, GROUP BY, funk­cje agre­gu­ją­ce, HAVING, SELECT, ORDER BY, LIMIT. Stąd dwie kon­se­kwen­cje, o które pytają ar­ku­sze:
  • W WHERE nie wolno użyć funk­cji agre­gu­ją­cej. W mo­men­cie, gdy działa WHERE, grup jesz­cze nie ma, więc WHERE COUNT(*) > 2 to błąd skład­ni.
  • W HAVING wolno użyć funk­cji agre­gu­ją­cej, bo grupy są już po­li­czo­ne. Można tam też po­sta­wić zwykły wa­ru­nek, ale fil­tro­wa­nie po­je­dyn­czych wier­szy należy do WHERE i jest szyb­sze.
Chcesz
Użyj
od­rzu­cić pro­duk­ty tańsze niż 30 zł
WHERE cena >= 30
zo­sta­wić ka­te­go­rie mające co naj­mniej 2 pro­duk­ty
HAVING COUNT(*) >= 2
zo­sta­wić ka­te­go­rie o śred­niej cenie po­wy­żej 100 zł
HAVING AVG(cena) > 100
Sor­to­wa­nie po wyniku funk­cji działa nor­mal­nie, także po nazwie nada­nej przez AS:
SELECT kategoria, SUM(cena) AS wartosc FROM produkt GROUP BY kategoria ORDER BY wartosc DESC;

Funk­cje tek­sto­we, licz­bo­we i daty

Poza agre­gu­ją­cy­mi MySQL ma funk­cje dzia­ła­ją­ce na POJEDYNCZEJ war­to­ści, wiersz po wier­szu. Na eg­za­mi­nie po­ja­wia­ją się w py­ta­niach „co zwróci funk­cja".
Funk­cja
Co robi
Przy­kład
Wynik
CONCAT(a, b)
skleja teksty
CONCAT('Monitor', ' 24')
Monitor 24
UPPER(t) / LOWER(t)
wiel­kie i małe litery
UPPER('mysz')
MYSZ
LENGTH(t)
dłu­gość w baj­tach; CHAR_LENGTH w zna­kach
CHAR_LENGTH('Mysz')
4
SUBSTRING(t, od, ile)
wy­ci­nek tekstu, li­czo­ny od 1
SUBSTRING('Klawiatura', 1, 4)
Klaw
REPLACE(t, co, czym)
pod­mia­na frag­men­tu
REPLACE('Monitor 24', '24', '27')
Monitor 27
TRIM(t)
usuwa spacje z brze­gów
TRIM(' mysz ')
mysz
ROUND(x, n)
za­okrą­gla do n miejsc
ROUND(63.333, 2)
63.33
CEIL(x) / FLOOR(x)
w górę i w dół do ca­ło­ści
CEIL(63.1)
64
MOD(a, b)
reszta z dzie­le­nia
MOD(7, 2)
1
NOW()
data i go­dzi­na teraz
NOW()
2026-09-07 12:30:00
CURDATE()
dzi­siej­sza data
CURDATE()
2026-09-07
YEAR(d), MONTH(d), DAY(d)
część daty
YEAR('2026-09-07')
2026
DATEDIFF(a, b)
róż­ni­ca w dniach
DATEDIFF('2026-09-10', '2026-09-07')
3
Funk­cje można za­gnież­dżać i łączyć z agre­gu­ją­cy­mi: ROUND(AVG(cena), 2) daje śred­nią za­okrą­glo­ną do groszy, co w za­da­niach wy­glą­da znacz­nie lepiej niż 63.333333.

Na eg­za­mi­nie

Py­ta­nia pi­sem­ne: „Które za­py­ta­nie zwróci liczbę uczniów w każdej klasie" (od­po­wiedź z GROUP BY), „Co zwróci COUNT(ocena), gdy dwa pola są puste", „Którą klau­zu­lą fil­tru­je się grupy" (od­po­wiedź HAVING) oraz ra­chun­ki z funk­cji tek­sto­wych, gdzie trzeba po­li­czyć znaki albo wska­zać wynik SUBSTRING.
W części prak­tycz­nej funk­cja agre­gu­ją­ca po­ja­wia się w kwe­ren­dzie opi­sa­nej sło­wa­mi: „wy­świetl liczbę wy­cie­czek w każdym kraju" albo „podaj śred­nią cenę noc­le­gu". Wzo­rzec jest zawsze ten sam: ko­lum­na gru­pu­ją­ca w SELECT i w GROUP BY, funk­cja obok niej.

Ściąga

Rzecz
Za­pa­mię­taj
liczba wier­szy
COUNT(*); z po­mi­nię­ciem NULL: COUNT(kolumna)
suma, śred­nia, skraj­ne
SUM, AVG, MIN, MAX; wszyst­kie po­mi­ja­ją NULL
po­dział na grupy
GROUP BY kolumna
co wolno w SELECT
ko­lum­ny z GROUP BY i funk­cje agre­gu­ją­ce
filtr wier­szy
WHERE, przed gru­po­wa­niem, bez funk­cji agre­gu­ją­cych
filtr grup
HAVING, po gru­po­wa­niu, z funk­cja­mi agre­gu­ją­cy­mi
ko­lej­ność
FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT
za­okrą­gle­nie śred­niej
ROUND(AVG(cena), 2)
Pobierz ściągę PDF
ZAWODNIK
egzamin zawodowy INF.02 · INF.03 · INF.04
Serwer Discord
Egzaminy zawodowe IT/Matury/Studia
@yastor
© 2026 Zawodnik · by Yastor
Arkusze i zasady oceniania pochodzą z CKE. Serwis nie jest powiązany z Centralną Komisją Egzaminacyjną.