SELECT sezon, SUM(liczba_dn) FROM rezerwacje GROUP BY sezon; Efektem wykonania kwerendy dla przedstawionej tabeli rezerwacje jest
SELECT sezon, SUM(liczba_dn) FROM rezerwacje GROUP BY sezon;Efektem wykonania kwerendy dla przedstawionej tabeli rezerwacje jest
| id_pok | liczba_dn | sezon |
|---|---|---|
| 1 | 10 | lato |
| 2 | 4 | zima |
| 1 | 5 | lato |
| 2 | 6 | zima |
| 1 | 5 | lato |
| 3 | 9 | zima |
| 1 | 8 | zima |
A. lato 10, zima 4, lato 5, zima 6, lato 5, zima 9, zima 8
B. lato 10, 5, 5; zima 4, 6, 9, 8
C. lato 3, zima 4
D. lato 20, zima 27
W tej kwerendzie kluczowe są dwa elementy: GROUP BY sezon oraz SUM(liczba_dn). Instrukcja GROUP BY nie pokazuje każdego rekordu osobno, tylko tworzy grupy rekordów mających taką samą wartość w kolumnie sezon. W tabeli są więc dwie grupy: lato i zima. Następnie funkcja agregująca SUM(liczba_dn) dodaje wartości z kolumny liczba_dn osobno dla każdej grupy. Dla sezonu lato mamy 10 + 5 + 5 = 20, a dla sezonu zima mamy 4 + 6 + 9 + 8 = 27. Dlatego wynikiem jest lato 20, zima 27. W praktyce taki zapis stosuje się bardzo często, np. do liczenia łącznej sprzedaży według miesiąca, sumy godzin pracy według pracownika albo liczby dni rezerwacji według sezonu. Moim zdaniem warto od razu wyrabiać sobie dobrą praktykę dodawania aliasu, np. SUM(liczba_dn) AS suma_dni, bo wynik jest wtedy czytelniejszy w aplikacji, raporcie lub panelu administratora. W SQL zgodnie z dobrymi zasadami każda kolumna w SELECT, która nie jest objęta funkcją agregującą, powinna występować w GROUP BY, i tutaj właśnie tak jest.
W tej sytuacji najczęstszy błąd polega na potraktowaniu zapytania tak, jakby baza danych miała tylko przepisać wiersze z tabeli. Gdyby zapytanie brzmiało SELECT sezon, liczba_dn FROM rezerwacje, wtedy rzeczywiście wynik zawierałby pary typu lato 10, zima 4 i tak dalej. Tutaj jednak użyto funkcji SUM, więc pojedyncze wartości z kolumny liczba_dn nie są wypisywane osobno, tylko są sumowane w obrębie grup. Samo GROUP BY sezon zmienia sposób myślenia o danych: baza najpierw dzieli rekordy na zestawy o takim samym sezonie, a potem liczy wynik agregacji dla każdego zestawu. Innym typowym nieporozumieniem jest uznanie, że wynik lato 3, zima 4 oznacza liczbę rekordów w każdym sezonie. To byłoby poprawne raczej dla COUNT(*), a nie dla SUM(liczba_dn). COUNT zlicza wiersze, natomiast SUM dodaje wartości liczbowe z wybranej kolumny. Jeszcze inna pułapka to wypisanie wartości jako listy, np. lato 10, 5, 5 oraz zima 4, 6, 9, 8. Standardowa funkcja SUM nie skleja wartości i nie tworzy listy, tylko zwraca jedną liczbę dla każdej grupy. Do łączenia tekstów służyłyby inne funkcje, zależne od systemu bazy danych, na przykład GROUP_CONCAT w MySQL. Kolumna id_pok w tym zapytaniu nie ma znaczenia, bo nie występuje ani w SELECT, ani w GROUP BY, ani w funkcji agregującej. Z mojego doświadczenia najlepiej przy takich zadaniach najpierw ręcznie pogrupować rekordy według wskazanej kolumny, a dopiero potem wykonać funkcję agregującą. Wtedy od razu widać, że lato daje 20, a zima 27.