Menu

Funkcje agregujące SQL w SQLite: COUNT, SUM, AVG, MIN, MAX

Jak funkcje agregujące w SQLite zamieniają wiele wierszy w jedną wartość: COUNT, SUM, AVG, MIN, MAX i GROUP_CONCAT, do tego DISTINCT, FILTER i zasady dotyczące NULL.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Co tak naprawdę robi funkcja agregująca

Większość funkcji SQL, które znasz do tej pory, działa wiersz po wierszu: UPPER(name) wykonuje się raz dla każdego wiersza, ROUND(price, 2) też raz dla każdego wiersza. Funkcje agregujące są inne. Patrzą na cały zbiór wierszy i sprowadzają go do jednej wartości.

Przygotuj małą tabelę do eksperymentów:

Wchodzi pięć wierszy, wychodzi jeden. Na tym polega cały model myślowy: funkcje agregujące zgniatają wiersze w podsumowanie. Bez GROUP BY podsumowanie obejmuje każdy wiersz wyniku.

COUNT: wiersze a wartości

COUNT ma trzy formy i różnica między nimi ma znaczenie:

  • COUNT(*) liczy wiersze. Razem z NULL. Zawsze zwraca liczbę.
  • COUNT(column) liczy wartości różne od NULL w tej kolumnie.
  • COUNT(DISTINCT column) liczy unikalne wartości różne od NULL.

Pięć wierszy, trzy z nich mają amount, trzech różnych klientów. Jeśli kiedyś zobaczysz, że COUNT(amount) jest mniejsze niż COUNT(*), to właśnie dlatego: NULL nie są liczone.

SUM, AVG, MIN, MAX

Arytmetyczne funkcje agregujące działają tak, jak się spodziewasz, z jedną cichą zasadą: wszystkie pomijają NULL:

AVG to (10 + 20 + 30) / 3 = 20.0, a nie 60 / 4 = 15.0. Mianownikiem jest liczba wartości różnych od NULL. Jeśli nie o to ci chodzi, bo wolisz traktować brakujące dane jako zero, zapisz to jawnie:

MIN i MAX działają też na tekście i datach: tekst porównują leksykograficznie, a daty w standardowym formacie jako ciągi ISO.

SUM a TOTAL

SQLite ma drugą funkcję agregującą podobną do sumy, TOTAL, która usuwa dwie niedogodności SUM:

  • SUM z zera wierszy zwraca NULL. TOTAL zwraca 0.0.
  • SUM z samych wartości NULL zwraca NULL. TOTAL zwraca 0.0.
  • TOTAL zawsze zwraca liczbę zmiennoprzecinkową, więc nigdy nie przepełnia arytmetyki całkowitoliczbowej.

Coś za coś: TOTAL nie jest standardowe, a wynik zawsze typu REAL może cię zaskoczyć, jeśli spodziewasz się liczby całkowitej. Sięgaj po nie, gdy "brak wierszy oznacza zero" to właściwa odpowiedź dla twojej aplikacji, a zostań przy SUM, gdy zależy ci na zachowaniu zgodnym ze standardem SQL.

DISTINCT wewnątrz funkcji agregujących

DISTINCT można wstawić do każdej funkcji agregującej, nie tylko do COUNT. Usuwa zduplikowane wartości przed wykonaniem agregacji:

SUM(amount) dodaje kwotę z każdego wiersza. SUM(DISTINCT amount) dodaje każdą unikalną kwotę raz. Przydaje się to na przykład przy "sumie unikalnych kwot faktur", ale rzadko jest tym, czego szukasz. Najczęściej używa się COUNT(DISTINCT customer).

FILTER: agregacja podzbioru

Gdy chcesz zagregować tylko część wierszy, oczywistym ruchem jest WHERE. Ale WHERE filtruje wszystko, więc w ten sposób nie połączysz w jednym zapytaniu "policz opłacone zamówienia" i "policz zwroty". Rozwiązaniem jest FILTER:

Każda klauzula FILTER (WHERE ...) dotyczy tylko tej jednej funkcji agregującej. Jedno przejście przez tabelę, kilka podsumowanych wycinków. Zanim pojawiło się FILTER, pisało się SUM(CASE WHEN status = 'paid' THEN amount END): ten sam pomysł, więcej pisania.

GROUP_CONCAT: łączenie tekstów

GROUP_CONCAT wyróżnia się na tle pozostałych. Zamiast liczby łączy wartości w jeden ciąg znaków:

Domyślnym separatorem jest przecinek. Podaj drugi argument, aby użyć czegoś innego. Kolejność nie jest gwarantowana, chyba że zapiszesz wywołanie jako GROUP_CONCAT(tag ORDER BY tag). To przydatne, gdy wynik pojawia się w interfejsie i ma być stabilny.

Agregacja bez GROUP BY

Każdy dotychczasowy przykład z funkcjami agregującymi bez GROUP BY zwracał dokładnie jeden wiersz. Taka jest zasada: SELECT z funkcjami agregującymi i bez GROUP BY to jednowierszowe podsumowanie całej tabeli (po zastosowaniu WHERE).

Funkcje agregujące możesz swobodnie łączyć:

Czego nie możesz zrobić, to mieszać kolumn niezagregowanych z funkcjami agregującymi i oczekiwać sensownych wyników:

-- SQLite na to pozwala, ale wartość `customer` jest przypadkowa.
SELECT customer, SUM(amount) FROM orders;

SQLite nie zgłosi tu błędu (inne bazy danych tak), ale pokaże obok sumy imię jakiegoś przypadkowego klienta. Jeśli chcesz sumę dla każdego klienta, potrzebujesz GROUP BY, któremu poświęcona jest następna strona.

Dalej: GROUP BY i HAVING

Funkcje agregujące na całej tabeli odpowiadają na pytanie "ile łącznie". Agregaty w grupach, na przykład na klienta, na miesiąc czy na status, odpowiadają na ciekawsze pytania. GROUP BY dzieli wiersze na koszyki przed agregacją, a HAVING filtruje po zagregowanym wyniku. To temat następnej strony.

Najczęściej zadawane pytania

Czym są funkcje agregujące w SQLite?

Funkcje agregujące przyjmują wiele wierszy i zwracają jedną wartość podsumowania. Wbudowane to COUNT, SUM, AVG, MIN, MAX, TOTAL i GROUP_CONCAT. Bez GROUP BY sprowadzają cały wynik do jednego wiersza.

Czym różni się SUM od TOTAL w SQLite?

Obie sumują liczby, ale SUM zwraca NULL, gdy każde wejście to NULL, i gdy to możliwe używa arytmetyki całkowitoliczbowej (która może się przepełnić). TOTAL zawsze zwraca liczbę zmiennoprzecinkową i daje 0.0, gdy nie ma żadnych wierszy. Używaj TOTAL, gdy potrzebujesz gwarantowanego wyniku liczbowego, a SUM, gdy liczy się zgodność ze standardem SQL.

Jak policzyć unikalne wartości w SQLite?

Wstaw DISTINCT do wywołania: COUNT(DISTINCT customer_id). Liczy to unikalne wartości różne od NULL. Zwykłe COUNT(column) liczy wartości różne od NULL razem z duplikatami, a COUNT(*) liczy każdy wiersz niezależnie od NULL.

Czy funkcje agregujące w SQLite pomijają NULL?

Tak, każda funkcja agregująca poza COUNT(*) pomija wejścia NULL. AVG dzieli przez liczbę wartości różnych od NULL, a nie przez łączną liczbę wierszy. Wyjątkiem jest COUNT(*): liczy wiersze, a nie wartości, więc NULL też są wliczane.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ