Kurz: Aggregatfunktionen fassen viele Zeilen zu einem Wert zusammen:
Teil des Kurses SQL
Aggregatfunktionen
Aggregatfunktionen fassen viele Zeilen zu einem Wert zusammen:
CREATE TABLE kunden (id INTEGER PRIMARY KEY, name TEXT NOT NULL, ort TEXT, punkte INTEGER);
CREATE TABLE bestellungen (id INTEGER PRIMARY KEY, kunde_id INTEGER, produkt TEXT, preis REAL, menge INTEGER, datum TEXT);
INSERT INTO kunden VALUES (1,'Mia','Berlin',120),(2,'Tom','Hamburg',80),(3,'Zoe','Berlin',200),(4,'Ben','München',NULL),(5,'Eva','Köln',150);
INSERT INTO bestellungen VALUES
(1,1,'Laptop',999.00,1,'2025-01-10'),(2,1,'Maus',25.50,2,'2025-01-12'),(3,2,'Monitor',189.90,1,'2025-02-01'),
(4,3,'Tastatur',49.00,1,'2025-02-15'),(5,3,'Maus',25.50,1,'2025-03-03'),(6,3,'Laptop',999.00,1,'2025-03-20'),
(7,NULL,'Kabel',5.00,3,'2025-03-21');
SELECT count(*) AS anzahl, count(punkte) AS mit_punkten, sum(punkte) AS summe,
avg(punkte) AS durchschnitt, min(punkte) AS minimum, max(punkte) AS maximum
FROM kunden;Ausgabe:
anzahl mit_punkten summe durchschnitt minimum maximum
------ ----------- ----- ------------ ------- -------
5 4 550 137.5 80 200count(*)zählt Zeilen,count(spalte)nur Zeilen mit Wert (nicht NULL)sum,avg,min,maxignorieren NULLcount(DISTINCT spalte)zählt verschiedene Werte
CREATE TABLE kunden (id INTEGER PRIMARY KEY, name TEXT NOT NULL, ort TEXT, punkte INTEGER);
CREATE TABLE bestellungen (id INTEGER PRIMARY KEY, kunde_id INTEGER, produkt TEXT, preis REAL, menge INTEGER, datum TEXT);
INSERT INTO kunden VALUES (1,'Mia','Berlin',120),(2,'Tom','Hamburg',80),(3,'Zoe','Berlin',200),(4,'Ben','München',NULL),(5,'Eva','Köln',150);
INSERT INTO bestellungen VALUES
(1,1,'Laptop',999.00,1,'2025-01-10'),(2,1,'Maus',25.50,2,'2025-01-12'),(3,2,'Monitor',189.90,1,'2025-02-01'),
(4,3,'Tastatur',49.00,1,'2025-02-15'),(5,3,'Maus',25.50,1,'2025-03-03'),(6,3,'Laptop',999.00,1,'2025-03-20'),
(7,NULL,'Kabel',5.00,3,'2025-03-21');
SELECT count(DISTINCT produkt) AS verschiedene, count(*) AS positionen,
sum(preis * menge) AS umsatz, round(avg(preis), 2) AS schnittspreis
FROM bestellungen;Ausgabe:
verschiedene positionen umsatz schnittspreis
------------ ---------- ------ -------------
5 7 2328.4 327.56GROUP BY: Gruppen bilden
CREATE TABLE kunden (id INTEGER PRIMARY KEY, name TEXT NOT NULL, ort TEXT, punkte INTEGER);
CREATE TABLE bestellungen (id INTEGER PRIMARY KEY, kunde_id INTEGER, produkt TEXT, preis REAL, menge INTEGER, datum TEXT);
INSERT INTO kunden VALUES (1,'Mia','Berlin',120),(2,'Tom','Hamburg',80),(3,'Zoe','Berlin',200),(4,'Ben','München',NULL),(5,'Eva','Köln',150);
INSERT INTO bestellungen VALUES
(1,1,'Laptop',999.00,1,'2025-01-10'),(2,1,'Maus',25.50,2,'2025-01-12'),(3,2,'Monitor',189.90,1,'2025-02-01'),
(4,3,'Tastatur',49.00,1,'2025-02-15'),(5,3,'Maus',25.50,1,'2025-03-03'),(6,3,'Laptop',999.00,1,'2025-03-20'),
(7,NULL,'Kabel',5.00,3,'2025-03-21');
SELECT ort, count(*) AS anzahl, sum(punkte) AS summe
FROM kunden
GROUP BY ort
ORDER BY anzahl DESC, ort;
SELECT produkt, count(*) AS verkauft, sum(menge) AS stueck, sum(preis * menge) AS umsatz
FROM bestellungen
GROUP BY produkt
ORDER BY umsatz DESC;Ausgabe:
ort anzahl summe
------- ------ -----
Berlin 2 320
Hamburg 1 80
Köln 1 150
München 1
produkt verkauft stueck umsatz
-------- -------- ------ ------
Laptop 2 2 1998.0
Monitor 1 1 189.9
Maus 2 3 76.5
Tastatur 1 1 49.0
Kabel 1 3 15.0Jede Spalte im SELECT ist entweder in GROUP BY oder in einer Aggregatfunktion. (SQLite erlaubt Abweichungen mit überraschendem Ergebnis, PostgreSQL meldet einen Fehler.)
HAVING: Gruppen filtern
WHERE filtert Zeilen vor dem Gruppieren, HAVING filtert Gruppen danach:
CREATE TABLE kunden (id INTEGER PRIMARY KEY, name TEXT NOT NULL, ort TEXT, punkte INTEGER);
CREATE TABLE bestellungen (id INTEGER PRIMARY KEY, kunde_id INTEGER, produkt TEXT, preis REAL, menge INTEGER, datum TEXT);
INSERT INTO kunden VALUES (1,'Mia','Berlin',120),(2,'Tom','Hamburg',80),(3,'Zoe','Berlin',200),(4,'Ben','München',NULL),(5,'Eva','Köln',150);
INSERT INTO bestellungen VALUES
(1,1,'Laptop',999.00,1,'2025-01-10'),(2,1,'Maus',25.50,2,'2025-01-12'),(3,2,'Monitor',189.90,1,'2025-02-01'),
(4,3,'Tastatur',49.00,1,'2025-02-15'),(5,3,'Maus',25.50,1,'2025-03-03'),(6,3,'Laptop',999.00,1,'2025-03-20'),
(7,NULL,'Kabel',5.00,3,'2025-03-21');
SELECT produkt, sum(menge) AS stueck
FROM bestellungen
WHERE preis < 500
GROUP BY produkt
HAVING sum(menge) >= 2
ORDER BY stueck DESC;Ausgabe:
produkt stueck
------- ------
Maus 3
Kabel 3Nach mehreren Spalten gruppieren
CREATE TABLE kunden (id INTEGER PRIMARY KEY, name TEXT NOT NULL, ort TEXT, punkte INTEGER);
CREATE TABLE bestellungen (id INTEGER PRIMARY KEY, kunde_id INTEGER, produkt TEXT, preis REAL, menge INTEGER, datum TEXT);
INSERT INTO kunden VALUES (1,'Mia','Berlin',120),(2,'Tom','Hamburg',80),(3,'Zoe','Berlin',200),(4,'Ben','München',NULL),(5,'Eva','Köln',150);
INSERT INTO bestellungen VALUES
(1,1,'Laptop',999.00,1,'2025-01-10'),(2,1,'Maus',25.50,2,'2025-01-12'),(3,2,'Monitor',189.90,1,'2025-02-01'),
(4,3,'Tastatur',49.00,1,'2025-02-15'),(5,3,'Maus',25.50,1,'2025-03-03'),(6,3,'Laptop',999.00,1,'2025-03-20'),
(7,NULL,'Kabel',5.00,3,'2025-03-21');
SELECT strftime('%Y-%m', datum) AS monat, produkt, count(*) AS anzahl
FROM bestellungen
GROUP BY monat, produkt
ORDER BY monat, produkt;Ausgabe:
monat produkt anzahl
------- -------- ------
2025-01 Laptop 1
2025-01 Maus 1
2025-02 Monitor 1
2025-02 Tastatur 1
2025-03 Kabel 1
2025-03 Laptop 1
2025-03 Maus 1Gruppen-Summen mit Bedingung
CREATE TABLE kunden (id INTEGER PRIMARY KEY, name TEXT NOT NULL, ort TEXT, punkte INTEGER);
CREATE TABLE bestellungen (id INTEGER PRIMARY KEY, kunde_id INTEGER, produkt TEXT, preis REAL, menge INTEGER, datum TEXT);
INSERT INTO kunden VALUES (1,'Mia','Berlin',120),(2,'Tom','Hamburg',80),(3,'Zoe','Berlin',200),(4,'Ben','München',NULL),(5,'Eva','Köln',150);
INSERT INTO bestellungen VALUES
(1,1,'Laptop',999.00,1,'2025-01-10'),(2,1,'Maus',25.50,2,'2025-01-12'),(3,2,'Monitor',189.90,1,'2025-02-01'),
(4,3,'Tastatur',49.00,1,'2025-02-15'),(5,3,'Maus',25.50,1,'2025-03-03'),(6,3,'Laptop',999.00,1,'2025-03-20'),
(7,NULL,'Kabel',5.00,3,'2025-03-21');
SELECT
sum(CASE WHEN preis >= 100 THEN 1 ELSE 0 END) AS teuer,
sum(CASE WHEN preis < 100 THEN 1 ELSE 0 END) AS guenstig,
group_concat(DISTINCT produkt) AS produkte
FROM bestellungen;Ausgabe:
teuer guenstig produkte
----- -------- ----------------------------------
3 4 Laptop,Maus,Monitor,Tastatur,Kabelgroup_concat (PostgreSQL: string_agg, MySQL: GROUP_CONCAT) verbindet Werte zu einem Text.
Merke
- Aggregate:
count,sum,avg,min,max,group_concat GROUP BYbildet Gruppen, jede Spalte imSELECTgehört inGROUP BYoder eine AggregatfunktionWHEREfiltert Zeilen,HAVINGfiltert Gruppencount(*)zählt Zeilen,count(spalte)nur Nicht-NULLCASEinnerhalb vonsumergibt bedingte Zählungen
Übungsaufgabe
Berechne je Kunde-ID Anzahl und Gesamtumsatz der Bestellungen und zeige nur Kunden mit mehr als 100 Umsatz.
Quiz zur Selbstkontrolle
Wo filterst du nach dem Ergebnis einer Aggregatfunktion?
- HAVING (richtig)
- WHERE
- GROUP BY
- ORDER BY
Was zählt count(spalte)?
- Nur Zeilen, bei denen die Spalte nicht NULL ist (richtig)
- Alle Zeilen
- Nur eindeutige Werte
- Nur NULL-Zeilen
Welche Klausel läuft zuerst: WHERE oder HAVING?
- WHERE (richtig)
- HAVING
- Beide gleichzeitig
- Es kommt auf die Schreibweise an
Weiter im Kurs
Zurück: Funktionen für Text, Zahlen, Datum und NULL
Weiter: Beziehungen und Fremdschlüssel
Alle Kapitel: SQL im Überblick