Aggregatfunktionen
to aggregate (engl.): anhäufen, vereinigen.
Jede Tabelle lässt sich nach einer Spalte gruppieren. Dabei werden alle Datensätze zu einer Gruppe zusammengefasst, die in der angegebenen Spalte denselben Wert haben. Mit einer Abfrage kann zunächst nur diese Spalte über eine Projektion ausgegeben werden.
Mithilfe von Aggregatfunktionen kann die Tabelle um zusätzlich mit neuen Informationen erweitert werden.
Diese Funktionen beziehen sich entweder
- auf die gesamte Selektion einer Anfrage oder
- auf Gruppen von Datensätzen, die mit
GROUP BYCOUNT(), SUM(), AVG(), MAX() und MIN()-
SQL92 spezifiziert die fünf Aggregatfunktionen.
1. SUM()
SUM() summiert die Werte einer Spalte (gegebenenfalls innerhalb einer Gruppe).
Beispiel: Tabelle
Kasseneinnahmen
| ID
|
KundenID
|
Beschreibung
|
Betrag
|
| 1
|
33
|
Ersatzgebühr
|
40
|
| 2
|
33
|
Mitgliederbeitrag
|
50
|
| 3
|
45
|
Mitgliederbeitrag
|
50
|
| 4
|
33
|
Mahngebühr
|
65
|
| 5
|
35
|
Kaution
|
20
|
| 6
|
59
|
Ersatzgebühr
|
40
|
| 7
|
45
|
Mahngebühr
|
80
|
| 8
|
45
|
Ersatzgebühr
|
40
|
Hier geben wir zu jeder Beschreibung einen eigenen summierten Betrag aus.
SELECT Beschreibung, SUM(Betrag)
FROM Kasseneinnahmen
GROUP BY Beschreibung;
Ergebnis:
| Beschreibung
|
SUM(Betrag)
|
| Ersatzgebühr
|
120
|
| Mitgliederbeitrag
|
100
|
| Mahngebühr
|
145
|
| Kaution
|
20
|
2. AVG()
AVG() berechnet pro Gruppe die Durchschnittswerte:
SELECT Beschreibung, AVG(Betrag)
FROM Kasseneinnahmen
GROUP BY Beschreibung;
Ergebnis:
| Beschreibung
|
AVG(Betrag)
|
| Ersatzgebühr
|
40
|
| Mitgliederbeitrag
|
50
|
| Mahngebühr
|
72.5
|
| Kaution
|
20
|
3. und 4. MAX() und MIN()
MIN() und
MAX() geben pro Gruppe die Minimal- und Maximalwerte aus:
SELECT Beschreibung, MIN(Betrag), MAX(Betrag)
FROM Kasseneinnahmen
GROUP BY Beschreibung;
Ergebnis:
| Beschreibung
|
MIN(Betrag)
|
MAX(Betrag)
|
| Ersatzgebühr
|
40
|
40
|
| Mitgliederbeitrag
|
50
|
50
|
| Mahngebühr
|
65
|
80
|
| Kaution
|
20
|
20
|
MAX() und
MIN() können aber auch auf nicht-numerische Spalten angewandt werden und suchen in diesem Fall nach der alphabetischen Ordnung oder nach der Datumsreihenfolge den Maximal- bzw. Minimalwert in einer Spalte. Schaue Dir dazu ein Beispiel unten an, in dem für die Tabelle
Kasseneinnahmen die alphabetisch höchsten und niedrigsten Werte geliefert werden.
SELECT MIN(Beschreibung), MAX(Beschreibung)
FROM Kasseneinnahmen;
| MIN(Beschreibung)
|
MAX(Beschreibung)
|
| Ersatzgebühr
|
Mitgliederbeitrag
|
5. Count()
COUNT() listet die Anzahl der Datensätze pro Gruppe auf:
SELECT Beschreibung, COUNT(Betrag)
FROM Kasseneinnahmen
GROUP BY Beschreibung;
Ergebnis:
| Beschreibung
|
COUNT(Betrag)
|
| Ersatzgebühr
|
3
|
| Mitgliederbeitrag
|
2
|
| Mahngebühr
|
2
|
| Kaution
|
1
|
Wie bereits beschrieben, ist es auch möglich, die gesamte Tabelle (oder die gesamte Ergebnisrelation) als eine Gruppe zu betrachten und insgesamt die Summe, den Durchschnittswert, den Minimal- und Maximalwert sowie die Anzahl auszugeben, indem man die Gruppierung ganz weg lässt:
SELECT SUM(Betrag), AVG(Betrag), MIN(Betrag), MAX(Betrag), COUNT(Betrag)
FROM Kasseneinnahmen;
| SUM(Betrag)
|
AVG(Betrag)
|
MIN(Betrag)
|
MAX(Betrag)
|
COUNT(Betrag)
|
| 385
|
48.125
|
20
|
80
|
8
|
NULL_Werte
NULL-Werte bei Aggregatfunktionen liefern auch dann Ergebnisse, wenn einige der Werte einer Gruppe den Wert NULL enthalten. Die fehlenden Einträge werden in der Endsumme nicht berücksichtigt. Wir verändern zur Veranschaulichung die Tabelle Kasseneinnahmen so, dass zwei Einträge NULL-Werte in der Spalte für Beträge enthalten, und führen noch einmal die obige SELECT-Anfrage aus.
Kasseneinnahmen:
| ID
|
KundenID
|
Beschreibung
|
Betrag
|
| 1
|
33
|
Ersatzgebühr
|
40
|
| 2
|
33
|
Mitgliederbeitrag
|
50
|
| 3
|
45
|
Mitgliederbeitrag
|
50
|
| 4
|
33
|
Mahngebühr
|
NULL
|
| 5
|
35
|
Kaution
|
NULL
|
| 6
|
59
|
Ersatzgebühr
|
40
|
| 7
|
45
|
Mahngebühr
|
80
|
| 8
|
45
|
Ersatzgebühr
|
40
|
SELECT SUM(Betrag), AVG(Betrag), MIN(Betrag), MAX(Betrag), COUNT(Betrag)
FROM Kasseneinnahmen;
Ergebnis:
| SUM(Betrag)
|
AVG(Betrag)
|
MIN(Betrag)
|
MAX(Betrag)
|
COUNT(Betrag)
|
| 300
|
50
|
40
|
80
|
6
|
Steht der
NULL-Wert in der Spalte, welche die Gruppierung bestimmt, wird dies als eine weitere Gruppe interpretiert. Hier ein Beispiel:
| ID
|
KundenID
|
Beschreibung
|
Betrag
|
| 1
|
33
|
Ersatzgebühr
|
40
|
| 2
|
33
|
Mitgliederbeitrag
|
50
|
| 3
|
45
|
Mitgliederbeitrag
|
50
|
| 4
|
33
|
Mahngebühr
|
NULL
|
| 5
|
35
|
Kaution
|
NULL
|
| 6
|
59
|
Ersatzgebühr
|
40
|
| 7
|
45
|
Mahngebühr
|
80
|
| 8
|
45
|
Ersatzgebühr
|
40
|
| 9
|
33
|
NULL
|
35
|
| 10
|
59
|
NULL
|
45
|
SELECT Beschreibung, SUM(Betrag), AVG(Betrag)
FROM Kasseneinnahmen GROUP BY Beschreibung;
Ergebnis:
| Beschreibung
|
SUM(Betrag)
|
AVG(Betrag)
|
| NULL
|
80
|
40
|
| Mahngebühr
|
80
|
80
|
| Kaution
|
NULL
|
NULL
|
| Mitgliederbeitrag
|
100
|
50
|
| Ersatzgebühr
|
120
|
40
|
Die Besonderheiten von COUNT()
Bei allen Aggregatfunktionen ist
NULL also ein Wert, welcher unerwartete Folgen auf das Ergebnis haben kann. Die einzige Standard-Aggregatfunktion, welche die Option der Berücksichtigung von
NULL-Werten anbietet, ist
COUNT().
COUNT() kann das so genannte Wildcardzeichen "*" verwenden, um die Berücksichtigung der
NULL-Werte zu erzwingen. Außerdem bietet sie mit den Schlüsselwörtern
DISTINCT und
ALL einige Anfragemöglichkeiten, die es bei den anderen Aggregatfunktionen nicht gibt. Sehen wir uns zuerst das Syntaxdiagramm zu den Standard-Aggregatfunktionen in SQL92 an.

Hier sind einige Beispiele, die wir auf die etwas veränderte Tabelle Kasseneinnahmen anwenden.
Kasseneinnahmen
| ID
|
Kunde
|
Beschreibung
|
Betrag
|
| 1
|
Betz
|
Ersatzgebühr
|
40
|
| 2
|
Betz
|
Mitgliederbeitrag
|
50
|
| 3
|
Polak
|
Mitgliederbeitrag
|
50
|
| 4
|
Betz
|
Mahngebühr
|
NULL
|
| 5
|
Kampinski
|
Kaution
|
NULL
|
| 6
|
Mayer
|
Ersatzgebühr
|
40
|
| 7
|
Polak
|
Mahngebühr
|
80
|
| 8
|
Polak
|
Ersatzgebühr
|
40
|
| 9
|
Betz
|
NULL
|
35
|
| 10
|
Mayer
|
Ersatzgebühr
|
45
|
| 11
|
Mayer
|
NULL
|
45
|
|
|
Mit Wildcard *
|
Ohne Wildcard
|
| Anfrage
|
SELECT COUNT(*), Beschreibung FROM Kasseneinnahmen GROUP BY Beschreibung;
|
SELECT COUNT(Betrag), Beschreibung FROM Kasseneinnahmen GROUP BY Beschreibung;
|
| Ergebnis
|
COUNT(*)
|
Beschreibung
|
| 4
|
Ersatzgebühr
|
| 1
|
Kaution
|
| 2
|
Mahngebühr
|
| 2
|
Mitgliederbeitrag
|
| 2
|
|
|
COUNT(Betrag)
|
Beschreibung
|
| 4
|
Ersatzgebühr
|
| 0
|
Kaution
|
| 1
|
Mahngebühr
|
| 2
|
Mitgliederbeitrag
|
| 2
|
|
|
Wie man sieht, werden bei dem Ergebnis ohne Wildcard die Datensätze mit dem Wert
NULL in der Spalte "Betrag" nicht in die Zählung einbezogen.
DISTINCT und ALL
Wenn man das Syntaxdiagramm genau betrachtet, wird auffallen, dass bei den Standard- Aggregatfunktionen innerhalb der Klammer die Schlüsselwörter DISTINCT und ALL verwendet werden können. ALL ist die Voreinstellung, falls keines der beiden angegeben wurde, und bedeutet, dass Wiederholungen innerhalb der Aggregatfunktion berücksichtigt werden. DISTINCT dagegen unterdrückt jegliche Wiederholung. Man könnte beispielsweise wissen wollen, zu wie vielen verschiedenen Beschreibungen jeder Kunde eingezahlt hat.
|
|
Mit DISTINCT
|
MIT ALL
|
| Anfrage
|
SELECT COUNT(DISTINCT Beschreibung), Kunde FROM Kasseneinnahmen GROUP BY Kunde;
|
SELECT COUNT(ALL Beschreibung), Kunde FROM Kasseneinnahmen GROUP BY Kunde;
|
| Ergebnis
|
COUNT(DISTINCT Beschreibung)
|
Kunde
|
| 3
|
Betz
|
| 3
|
Polak
|
| 1
|
Kampinski
|
| 1
|
Mayer
|
|
COUNT(ALL Beschreibung)
|
Kunde
|
| 3
|
Betz
|
| 3
|
Polak
|
| 1
|
Kampinski
|
| 2
|
Mayer
|
|
Beachte den Eintrag für "Mayer" in beiden Ergebnissen. Links liegt der Wert, den
COUNT() liefert, bei 1, rechts bei 2. "Mayer" hat zweimal "Ersatzgebühr" zahlen müssen.
DISTINCT unterdrückt die Wiederholung, also wissen wir, dass die Tabelle für "Mayer" Einträge mit nur einer Art von Beschreibung enthält (in diesem Fall ist es "Ersatzgebühr"). Mit
ALL wird jedes einzelne Vorkommen einer Beschreibung berücksichtigt; also auch, dass Mayer zweimal die "Ersatzgebühr" hat zahlen müssen. Die Einträge mit
NULL-Werten werden nicht berücksichtigt, da keine Wildcard "*" verwendet wird.
DISTINCT macht bei den anderen vier Standard-Aggregatfunktionen selten einen Sinn.
SUM(DISTINCT Betrag) gruppiert nach den Beschreibungen. Mayer würde nur eine Gebühr von Euro 45,- zahlen, auch wenn es mehrere Zahlungen in dieser Höhe geben würde, wie folgendes Beispiel demonstriert:
Kasseneinnahmen
| ID
|
Kunde
|
Beschreibung
|
Betrag
|
| 1
|
Betz
|
Ersatzgebühr
|
40
|
| 2
|
Betz
|
Mitgliederbeitrag
|
50
|
| 3
|
Polak
|
Mitgliederbeitrag
|
50
|
| 4
|
Betz
|
Mahngebühr
|
NULL
|
| 5
|
Kampinski
|
Kaution
|
NULL
|
| 6
|
Mayer
|
Ersatzgebühr
|
40
|
| 7
|
Polak
|
Mahngebühr
|
80
|
| 8
|
Polak
|
Ersatzgebühr
|
40
|
| 9
|
Betz
|
NULL
|
35
|
| 10
|
Mayer
|
Ersatzgebühr
|
45
|
| 11
|
Mayer
|
NULL
|
45
|
SELECT SUM(DISTINCT Betrag), Kunde
FROM Kasseneinnahmen
GROUP BY Kunde;
Ergebnis:
SUM(DISTINCT BETRAG)
|
KUNDE
|
| 125
|
Betz
|
| NULL
|
Kampinski
|
| 85
|
Mayer
|
| 170
|
Polak
|
Es wird mit der obigen
SELECT-Anfrage jede Zahl in der Gruppe der Kunden nur einmal zur Gesamtsumme gerechnet. Für die drei Einträge von "Mayer" bedeutet dies, dass der Eintrag 6 in Spalte
ID mit "40" und einer der Einträge 10 oder 11 in Spalte
ID (aber nicht beide) zur Gesamtsumme "85" berechnet wird. Es gibt selten eine Anwendung, die solche Geschäftsbedingungen erfordert.
Weitere Aggregatfunktionen
Außer den Standard-Aggregatfunktionen, die in SQL92 spezifiziert sind, implementieren die Hersteller einige weitere Funktionen wie
STDDEV() für die Standard-Abweichung und
VARIANCE() für die Streuung. MySQL implementiert sogar Aggregatfunktionen für die bitweise Verknüpfung von Zahlenwerten; dies sind allerdings Funktionen für sehr ausgefallene Anwendungen, die in einem Einführungskurs kaum Platz haben, weshalb wir hier auf eine nähere Beschreibung verzichten werden.