Aggregation und Gruppierung in SQL
AnfängerEinheit 4 von 6 in Kurs: SQL – Datenbanken abfragen mit SELECT, JOIN und GROUP BY
Was du lernst
- Fasse viele Zeilen mit COUNT, SUM, AVG, MIN und MAX zu Werten zusammen, wähle die passende Zählweise und sage vorher, wie fehlende Werte ein Ergebnis verändern.
- Summen, Durchschnitte, kleinste und größte Werte ermittelnVerwende SUM, AVG, MIN und MAX auf einer ganzen Tabelle oder auf den von einer WHERE-Klausel beibehaltenen Zeilen und kombiniere mehrere davon in einer Abfrage.
- Zeilen, Werte und unterschiedliche Werte zählenWähle zwischen COUNT(*), COUNT(Spalte) und COUNT(DISTINCT Spalte) und lerne, wie jede Variante wiederholte und fehlende Werte behandelt.
- Vorhersagen, wie sich NULL-Werte auf Aggregate auswirkenLerne, dass Aggregate NULL-Werte überspringen, sage Ergebnisse für leere Eingabemengen vorher und ersetze NULL durch einen Ersatzwert, wenn die Frage es verlangt.
- Summen, Durchschnitte, kleinste und größte Werte ermitteln
- Verwende GROUP BY für eine zusammenfassende Zeile pro Kategorie, pro Wertekombination oder pro berechnetem Wert und beachte die Regel, was eine gruppierte Abfrage anzeigen darf.
- Jede Kategorie mit GROUP BY zusammenfassenTeile eine Tabelle in Gruppen mit einem gemeinsamen Wert auf, berechne Aggregate pro Gruppe und sortiere und begrenze das gruppierte Ergebnis.
- Die Regel beachten, was eine gruppierte Abfrage anzeigen darfLerne, welche Spalten in der SELECT-Liste einer gruppierten Abfrage stehen dürfen, behebe den Fehler bei einem Regelverstoß und erkenne Unterschiede zwischen Datenbanken.
- Nach mehreren Spalten und nach berechneten Werten gruppierenGruppiere Zeilen nach Spaltenkombinationen und nach Ausdrücken wie dem Monat eines Datums oder einer CASE-Kategorie und lies das detailliertere Ergebnis.
- Jede Kategorie mit GROUP BY zusammenfassen
- Behalte nur die Gruppen, deren Summen, Anzahlen oder Durchschnitte eine Bedingung erfüllen, und entscheide, ob eine Bedingung in WHERE oder HAVING gehört.
- Nur die Gruppen behalten, die eine Bedingung erfüllenSchreibe HAVING-Bedingungen für Aggregatwerte, einschließlich nicht angezeigter Aggregate, um ein gruppiertes Ergebnis zu filtern.
- Zwischen WHERE und HAVING wählenEntscheide anhand der logischen Reihenfolge einer Abfrage, ob eine Bedingung Zeilen oder Gruppen filtert, und sage vorher, wie diese Wahl das Ergebnis verändert.
- Nur die Gruppen behalten, die eine Bedingung erfüllen
- Vermeide ganzzahlige Division, lerne den Zahlentyp kennen, den jedes Aggregat zurückgibt, und runde Durchschnitte, Summen und Prozentwerte zum richtigen Zeitpunkt.
- Ganzzahlige Division bei Durchschnitten und Prozentwerten vermeidenErkenne, wann bei der Division von Aggregaten Nachkommastellen verloren gehen, behebe dies mit einem Dezimaloperanden und lerne, wie sich Ergebnistypen zwischen Datenbanken unterscheiden.
- Aggregierte Ergebnisse rundenRunde Durchschnitte, Summen und Prozentwerte mit ROUND zum richtigen Zeitpunkt und gehe mit den Unterschieden zwischen SQLite und PostgreSQL um.
- Ganzzahlige Division bei Durchschnitten und Prozentwerten vermeiden
- Kombiniere CASE mit Aggregaten für bedingte Zählungen, Summen und Prozentwerte und übersetze eine Frage in eine gruppierte Abfrage, deren Zahlen du prüfen kannst.
- Mit CASE bedingt zählen und summierenSetze einen CASE-Ausdruck in ein Aggregat, um mehrere bedingte Zählungen, Summen und Prozentwerte in einer gruppierten Abfrage zu berechnen.
- Aus einer Frage eine zusammenfassende Abfrage erstellen und prüfenÜbersetze eine geschäftliche Frage Schritt für Schritt in eine gruppierte Abfrage, vermeide es, Detailebenen zu vermischen, und prüfe, ob die Zahlen stimmen.
- Mit CASE bedingt zählen und summieren
SQL-Aggregation einfach erklärt
1Daten mit Aggregatfunktionen zusammenfassen
Eine Tabelle erfasst einzelne Ereignisse; ein Bericht benötigt oft einige Zahlen, die sie zusammen beschreiben. Aggregatfunktionen machen aus Zeilen Anzahlen, Summen, Durchschnitte und Extremwerte. Die Wahl der Funktion ist nur ein Teil der Aufgabe: Du musst auch entscheiden, welche Zeilen in die Berechnung gehören und was fehlende Werte bedeuten. An einer kleinen Bestelltabelle prüfen wir jede Antwort von Hand, bevor wir uns auf die Abfrage verlassen.
1.1 Summen, Durchschnitte, kleinste und größte Werte ermitteln
Eine Aggregatfunktion fasst Werte aus vielen Zeilen zu einem Ergebnis zusammen. Oracle nennt sie auch Gruppenfunktion. Ohne GROUP BY behandelt eine Aggregatabfrage alle Zeilen, die WHERE passieren, als eine Gruppe und gibt eine zusammenfassende Zeile zurück.
Beginne mit Daten, die du prüfen kannst
Jede Zeile in orders ist eine Bestellung. Die numerischen Spalten unten enthalten ganze Zahlen; order_id ist der Primärschlüssel. Datumswerte werden in SQLite als ISO-Text und in PostgreSQL mit dem Typ DATE gespeichert.
| order_id | customer | region | amount | quantity | discount | order_date |
|---|---|---|---|---|---|---|
| 1 | Ana | East | 120 | 2 | 10 | 2026-01-05 |
| 2 | Ben | West | 80 | 1 | NULL | 2026-01-17 |
| 3 | Ana | East | 45 | 3 | 5 | 2026-02-02 |
| 4 | Chen | North | 200 | 4 | NULL | 2026-02-14 |
| 5 | Ben | West | 60 | 1 | 0 | 2026-02-20 |
| 6 | Dara | East | 95 | 2 | NULL | 2026-03-03 |
| 7 | Chen | North | 150 | 5 | 15 | 2026-03-09 |
| 8 | Eli | NULL | 30 | 1 | NULL | 2026-03-21 |
Wähle die Kennzahl
SUM(amount) addiert die Beträge. AVG(amount) ergibt ihr arithmetisches Mittel. MIN(amount) ermittelt den kleinsten und MAX(amount) den größten Betrag. Du kannst alle vier in einer Abfrage anfordern:
SELECT SUM(amount) AS total, AVG(amount) AS avg_amount, MIN(amount) AS smallest, MAX(amount) AS largest FROM orders;
Das Ergebnis ist eine Zeile: Summe 780, Durchschnitt 97,5, kleinster Wert 30 und größter Wert 200. Addiere die acht Beträge, um 780 zu erhalten, und teile dann durch acht für 97,5. Jede Funktion verarbeitet dieselben acht Eingabezeilen. Aussagekräftige Aliase nach AS machen die Ausgabeüberschriften nützlich; eine erzeugte Überschrift wie sum sagt wenig darüber aus, was addiert wurde.
Filtere vor der Berechnung
Um Bestellungen aus East zusammenzufassen, schreibe SELECT COUNT(*) AS orders, SUM(amount) AS total FROM orders WHERE region = 'East';. Der Filter behält die Beträge 120, 45 und 95. Die Abfrage gibt drei Bestellungen und eine Summe von 260 zurück. WHERE wählt die Eingabezeilen aus, bevor ein Aggregat berechnet wird.
Ein Aggregat kann auch einen berechneten Ausdruck als Argument nehmen. In einer Tabelle mit quantity und unit_price ermittelt SUM(quantity * unit_price) zunächst den Umsatz jeder Zeile und addiert ihn dann. Zwei Zeilen, zwei Artikel zu 5 und drei Artikel zu 10, tragen 10 und 30 bei, zusammen 40. SUM(quantity) * SUM(unit_price) multipliziert dagegen 5 mit 15 und ergibt 75. Steht die Berechnung innerhalb von SUM, bleibt jede Menge dem passenden Preis zugeordnet.
Lies Extremwerte richtig
MIN(order_date) ist 2026-01-05 und MAX(order_date) ist 2026-03-21. Datumswerte und ISO-Datumstext werden chronologisch sortiert. Text wie '03/21/2026' folgt der Zeichenreihenfolge, die nicht zuverlässig der Datumsreihenfolge entspricht. Auch Extremwerte bei Text folgen der Sortierfolge der Datenbank, also ihren Regeln zum Vergleichen von Text. Hier sind die Extremwerte der Kundennamen 'Ana' und 'Eli'; unterschiedliche Groß- und Kleinschreibung kann die Textsortierung verändern.
MAX(amount) gibt einen Betrag zurück, nicht die ganze Bestellung, die ihn enthält. Um einen Kunden mit einer größten Bestellung anzuzeigen, verwende SELECT customer, amount FROM orders ORDER BY amount DESC LIMIT 1;. PostgreSQL lehnt eine gewöhnliche Spalte customer neben MAX(amount) ohne passende Gruppierung ab. SQLite hat eine Sonderregel für ein einzelnes MIN oder MAX, die eine benachbarte Spalte aus der Zeile mit dem Extremwert zurückgeben kann; bei gleichen Extremwerten wird aber weiterhin eine Regel für den Gleichstand benötigt.
Wichtige Erkenntnisse
- Ein Aggregat gibt für eine Gruppe von Zeilen einen Wert zurück.
WHEREwählt die Zeilen aus, die das Aggregat verarbeitet.- Berechne den Beitrag jeder Zeile innerhalb von
SUM, wenn Werte einander zugeordnet bleiben müssen. MINundMAXfolgen der Sortierung von Zahlen, Datumswerten oder Text.- Ein Extremwert identifiziert keine ganze Zeile.
1.2 Zeilen, Werte und unterschiedliche Werte zählen
„Wie viele?“ kann sich auf Zeilen, erfasste Werte oder unterschiedliche Werte beziehen. Das sind verschiedene Zählweisen, auch wenn sie in einer kleinen Tabelle zufällig dieselbe Zahl ergeben.
Drei Formen von COUNT
| Ausdruck | Was er zählt |
|---|---|
COUNT(*) | Jede Eingabezeile |
COUNT(region) | Zeilen mit einer Region, die nicht NULL ist |
COUNT(DISTINCT region) | Unterschiedliche Regionswerte ohne NULL |
In der Bestelltabelle lauten die Regionen East, West, East, North, West, East, North und NULL. SELECT COUNT(*) AS order_rows, COUNT(region) AS with_region, COUNT(DISTINCT region) AS regions FROM orders; gibt 8, 7 und 3 zurück. Die wiederholten Regionsnamen werden bei COUNT(region) einzeln gezählt, aber jeder Name trägt nur einmal zur Anzahl unterschiedlicher Werte bei.
Für „Wie viele verschiedene Kunden haben bestellt?“ verwende COUNT(DISTINCT customer). Ana, Ben und Chen kommen jeweils zweimal vor, Dara und Eli jeweils einmal, die Antwort lautet also fünf Kunden. COUNT(customer) gibt acht zurück, weil jede Bestellung einen Kunden nennt. Es zählt Bestellzeilen mit Kundennamen, nicht Personen.
Eine erfasste Null zählt mit
Die Rabatte sind 10, NULL, 5, NULL, 0, NULL, 15 und NULL. COUNT(discount) gibt vier zurück. Die Null erfasst einen bekannten Wert und zählt genauso wie 10, 5 und 15. Eine leere Zeichenkette ist in SQLite und PostgreSQL ebenfalls ein Wert; Oracle behandelt eine leere Zeichenkette als NULL.
Ziehe die Anzahl der Werte ohne NULL von der Zeilenanzahl ab, um fehlende Einträge zu zählen: SELECT COUNT(*) - COUNT(region) AS missing_region FROM orders; gibt eins zurück. Das funktioniert, weil beide Zählungen genau dieselben Eingabezeilen verwenden.
DISTINCT-Listen und Anzahlen unterschiedlicher Werte
SELECT DISTINCT region FROM orders; listet East, West, North und eine NULL-Zeile auf. Die Abfrage soll unterschiedliche Werte zurückgeben, und NULL bleibt in dieser Liste. COUNT(DISTINCT region) gibt drei zurück, weil die Zählung NULL ignoriert. Schließe nicht durch Zählen einer Liste auf die Anzahl unterschiedlicher Werte, ohne zu entscheiden, ob ihre NULL-Zeile dazugehört.
DISTINCT kann auch innerhalb von SUM oder AVG stehen. Die Mengen sind 2, 1, 3, 4, 1, 2, 5 und 1. Ihre gewöhnliche Summe ist 19. SUM(DISTINCT quantity) behält nur 1, 2, 3, 4 und 5 und ergibt 15. Wiederholte Mengen stehen gewöhnlich für tatsächliche zusätzliche Verkäufe. Entfernst du sie, ändert sich die Kennzahl; doppelte Datensätze werden dadurch nicht korrigiert.
Kombinationen in zwei Schritten zählen
Erstelle für unterschiedliche Paare aus Region und Kunde zunächst eine Liste unterschiedlicher Werte:
SELECT COUNT(*) FROM (SELECT DISTINCT region, customer FROM orders) AS pairs;
Die innere Abfrage gibt fünf Paare zurück: East/Ana, East/Dara, North/Chen, West/Ben und NULL/Eli. Das äußere COUNT(*) zählt diese fünf Zeilen einschließlich NULL/Eli. Diese Form funktioniert in SQLite und PostgreSQL. MySQL akzeptiert auch COUNT(DISTINCT region, customer), aber diese Form schließt Kombinationen mit NULL aus und kann daher eine andere Frage beantworten. In SQLite und PostgreSQL ist die durch Kommas getrennte Form unzulässig.
Eine Zählung gibt niemals NULL zurück. SELECT COUNT(*) FROM orders WHERE region = 'South'; gibt eine zusammenfassende Zeile mit null zurück, weil es keine passenden Bestellungen gibt.
Wichtige Erkenntnisse
- Wähle zwischen Zeilen, erfassten Werten und unterschiedlichen erfassten Werten.
- Null ist ein erfasster Wert, daher zählt
COUNT(column)sie mit. - Eine Liste unterschiedlicher Werte kann NULL enthalten;
COUNT(DISTINCT column)überspringt NULL. SUM(DISTINCT x)entfernt wiederholte Werte, auch berechtigte Wiederholungen.- Zähle unterschiedliche Kombinationen, indem du ein inneres Ergebnis mit unterschiedlichen Werten zählst.
COUNTgibt bei einer leeren Eingabemenge null zurück.
1.3 Vorhersagen, wie sich NULL-Werte auf Aggregate auswirken
NULL bedeutet, dass ein Wert fehlt oder unbekannt ist. Es verändert, welche Werte in ein Aggregat eingehen. Daher kann eine Summe oder ein Durchschnitt gültiges SQL sein und dennoch etwas anderes messen als beabsichtigt.
Bestimme den Nenner
Angenommen, scores enthält Ana 80, Ben NULL, Chen 70 und Dara 90. SUM(score) ist 240, COUNT(score) ist drei und COUNT(*) ist vier. AVG(score) ist 80: Die drei erfassten Punktzahlen ergeben zusammen 240 und werden durch drei geteilt.
Die fünf Standardaggregate ignorieren NULL-Argumente. COUNT(*) zählt jede Zeile, weil es kein Spaltenargument auswertet. MIN(score) ist 70 und MAX(score) ist 90; NULL wird weder zur kleinsten noch zur größten Punktzahl. Das unterscheidet sich vom Sortieren, bei dem NULL-Werte an einem Ende des Ergebnisses stehen: bei aufsteigender Sortierung in SQLite zuerst, in PostgreSQL zuletzt.
Für einen von Hand berechneten Durchschnitt wird die Anzahl der Werte ohne NULL benötigt: 1.0 * SUM(score) / NULLIF(COUNT(score), 0). Der Dezimaloperand erhält Nachkommastellen im Ergebnis, und NULLIF macht einen Divisor von null zu NULL. Eine Division durch COUNT(*) würde 60 ergeben und die fehlende Punktzahl damit wie null behandeln.
Entscheide, was ein Ersatzwert bedeutet
COALESCE gibt das erste Argument zurück, das nicht NULL ist. Wenn Ben noch nicht bewertet wurde, lass die Punktzahl fehlen und berechne den Durchschnitt der bekannten Ergebnisse. Wenn eine versäumte Prüfung als NULL erfasst ist, aber als null zählen muss, bildet AVG(COALESCE(score, 0)) den Durchschnitt von 80, 0, 70 und 90 und ergibt 60. Die Bedeutung der Daten entscheidet, ob diese Ersetzung gerechtfertigt ist.
Vergleiche COALESCE innerhalb und außerhalb einer Funktion. AVG(COALESCE(score, 0)) verändert die Werte, die in den Durchschnitt eingehen. COALESCE(AVG(score), 0) verändert nur ein NULL-Endergebnis; für diese Punktzahlen ergibt es weiterhin 80. Oracles NVL(x, 0) ist eine weitere Form mit zwei Argumenten, um NULL zu ersetzen.
Unterscheide keine Zeilen von keinen erfassten Werten
Bei WHERE region = 'South' bleiben keine Bestellungen übrig. Eine Aggregatabfrage ohne GROUP BY gibt dennoch eine Zeile zurück: COUNT(*) ist null, während SUM(amount), AVG(amount), MIN(amount) und MAX(amount) NULL sind. Um eine leere Summe als null anzuzeigen, verwende COALESCE(SUM(amount), 0). SQLite bietet auch TOTAL(amount) an, das bei leerer Eingabemenge 0,0 zurückgibt.
Betrachte nun die vier Bestellungen, deren Rabatt NULL ist. Es gibt Zeilen, aber keine erfassten Rabattwerte: COUNT(*) ist vier, COUNT(discount) ist null und SUM(discount) ist NULL. Null erfasste Werte und vier fehlende Werte sind unterschiedliche Beobachtungen.
Prüfe Ausdrücke, bevor sie in SUM eingehen
Rechnen mit NULL ergibt NULL. In SUM(amount - discount) tragen die vier Bestellungen ohne erfassten Rabatt überhaupt keinen Wert bei. Nur die Zeilen mit bekanntem Rabatt tragen bei: 110, 40, 60 und 135, zusammen 345.
Wenn ein fehlender Rabatt bedeutet, dass kein Rabatt gewährt wurde, schreibe SUM(amount - COALESCE(discount, 0)). Dann trägt jede Bestellung bei; der Gesamtbetrag 780 abzüglich der erfassten Rabatte 30 ergibt 750. Ein COALESCE um die gesamte Summe würde die ausgelassenen Bestellungen nicht zurückbringen, weil 345 bereits nicht NULL ist.
Um fehlende Werte zu finden, verwende IS NULL oder IS NOT NULL. WHERE discount IS NULL findet vier Bestellungen. discount = NULL ist niemals wahr und kann sie daher nicht auswählen.
Wichtige Erkenntnisse
AVG(x)teilt durch die Anzahl der Werte ohne NULL.- Ein inneres
COALESCEverändert die Eingabewerte; ein äußeres verändert ein NULL-Ergebnis. - Eine leere Eingabemenge ergibt null für
COUNTund NULL für die anderen vier Aggregate. - NULL innerhalb eines arithmetischen Ausdrucks kann den Beitrag einer Zeile entfallen lassen.
2Zeilen gruppieren und jede Gruppe zusammenfassen
Eine Summe über die ganze Tabelle beantwortet eine Frage, aber viele Berichte benötigen ein Ergebnis pro Kunde, Region oder Monat. Die Gruppierung legt diese Detailebene fest, bevor die Aggregate berechnet werden. Du verfolgst, wie Zeilen zu Gruppen werden, wählst Spalten aus, die eine ganze Gruppe beschreiben können, und siehst, wie eine zusätzliche Gruppierungsspalte den Bericht verändert. Die Sortierung bestimmt anschließend die Darstellung der Ergebnisse; die Gruppierung allein legt keine Reihenfolge fest.
2.1 Jede Kategorie mit GROUP BY zusammenfassen
GROUP BY fasst Zeilen mit demselben Gruppierungswert zusammen. Jedes Aggregat wird innerhalb jeder Gruppe getrennt berechnet, und die Ausgabe enthält eine Zeile für jede nach dem Filtern vorhandene Gruppe.
Entscheide, was eine Ergebniszeile bedeutet
„Gesamtumsatz pro Region“ verlangt eine Ausgabezeile pro Region. Schreibe zunächst diesen Satz auf und verwende dann region als Gruppierungsspalte:
SELECT region, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY region;
Die drei Beträge aus East, 120, 45 und 95, bilden eine Gruppe. Ihre Anzahl ist drei und ihre Summe 260. North hat zwei Bestellungen mit zusammen 350; West hat zwei mit zusammen 140. Elis Bestellung bildet eine Gruppe mit NULL als Region, einer Bestellung und einer Summe von 30. Es gibt vier Ergebniszeilen, nicht acht.
Lies die Abfrage als Abfolge: FROM liefert Bestellungen, ein vorhandenes WHERE entfernt Zeilen, GROUP BY fasst die verbleibenden Zeilen nach Region zusammen und die Aggregate fassen jede Gruppe zusammen. SELECT zeigt ihre Beschriftung und Kennzahlen an. Die Gruppierung verwirft die kleineren Bestellungen innerhalb einer Gruppe nicht; sie tragen alle bei, sofern sie nicht durch einen Zeilenfilter entfernt wurden.
Halte fehlende Kategorien sichtbar
Zeilen mit NULL in der Gruppierungsspalte gehören zu einer NULL-Gruppe. Das ist nützlich: Ein Bericht kann zeigen, wie viel Aktivität keiner erfassten Region zugeordnet ist. Er behandelt nicht jede fehlende Region als eigene Kategorie.
Um eine lesbare Beschriftung anzuzeigen, wähle COALESCE(region, 'No region') AS region_label und behalte GROUP BY region bei. Die Beschriftung verändert den angezeigten Wert. Um diese Zeilen aus den Berechnungen auszuschließen, ergänze WHERE region IS NOT NULL vor GROUP BY. Die resultierenden Summen ergeben zusammen 750, weil Elis Betrag von 30 ausgelassen wurde.
Eine gruppierte Abfrage über eine Eingabemenge ohne Zeilen gibt keine Gruppen zurück. Filtert man die Tabelle beispielsweise auf South und gruppiert dann nach Region, erhält man keine Ergebniszeilen. Das unterscheidet sich von einem Aggregat über die ganze Tabelle ohne GROUP BY, das selbst bei leerer Eingabemenge eine zusammenfassende Zeile erzeugt.
Sortiere die Gruppen ausdrücklich
GROUP BY garantiert keine Ausgabereihenfolge. Um die größten Regionen zuerst aufzulisten, ergänze ORDER BY total DESC. Der Alias total ist in ORDER BY erlaubt; ORDER BY SUM(amount) DESC ergibt dieselbe Sortierung.
Ein Kundenbericht kann die drei größten Summen auswählen:
SELECT customer, SUM(amount) AS total FROM orders GROUP BY customer ORDER BY total DESC, customer LIMIT 3;
Er gibt Chen 350, Ana 165 und Ben 140 zurück. Das zweite Sortierkriterium, customer, sorgt bei gleichen Summen für eine wiederholbare Reihenfolge. LIMIT 3 gibt nur drei Zeilen zurück; es behält nicht alle gleichen Werte am Grenzwert. SQL Server drückt diese Begrenzung mit SELECT TOP 3 aus, während Oracle FETCH FIRST 3 ROWS ONLY unterstützt.
Beim aufsteigenden Sortieren von Kategorienamen setzt SQLite NULL normalerweise an den Anfang und PostgreSQL an das Ende. Gib die gewünschte Sortierung an, wenn die Position wichtig ist.
Prüfe die Gruppierungsspalte
SELECT DISTINCT region FROM orders und SELECT region FROM orders GROUP BY region geben dieselben unterschiedlichen Regionsbezeichnungen einschließlich NULL zurück. Verwende eine Gruppierung, wenn du auch eine Kennzahl für jede Bezeichnung benötigst.
Die Gruppierung nach der eindeutigen order_id ergibt acht Gruppen mit je einer Zeile. Jede Anzahl ist eins, und jede Betragssumme entspricht dem Betrag der jeweiligen Zeile. Für einen regionalen Bericht zeigt dieses Ergebnis, dass die Gruppierungsspalte zu detailliert ist.
Wichtige Erkenntnisse
- Formuliere, wofür eine Ausgabezeile steht, bevor du
GROUP BYfestlegst. - Alle NULL-Gruppierungswerte bilden eine Gruppe.
- Verwende
ORDER BYfür die Ergebnisreihenfolge und ein zweites Kriterium für gleiche Werte. - Die Gruppierung nach einem eindeutigen Zeilenschlüssel ergibt Gruppen mit je einer Zeile.
2.2 Die Regel beachten, was eine gruppierte Abfrage anzeigen darf
Ein gruppierter Bericht muss viele Eingabezeilen in einer Ergebniszeile zusammenfassen. Jeder angezeigte Wert benötigt daher eine klare Bedeutung für die ganze Gruppe. Deshalb schränkt SQL ein, welche Spalten du auswählen kannst.
Beachte die übertragbare Gruppierungsregel
Ein Eintrag in einem gruppierten SELECT sollte eine Gruppierungsspalte, ein aus Gruppierungsspalten gebildeter Ausdruck, ein Aggregat oder eine Konstante sein. Betrachte:
SELECT region, customer, COUNT(*) FROM orders GROUP BY region;
East enthält Ana, Ana und Dara. Die Gruppe hat eine Region und eine Anzahl, aber zwei verschiedene Kundennamen. Die Abfrage legt nicht fest, welchen Kunden eine einzelne Ergebniszeile für East anzeigen soll. PostgreSQL lehnt die nicht gruppierte Spalte customer ab.
Dasselbe Problem tritt ohne GROUP BY auf: SELECT customer, SUM(amount) FROM orders kombiniert eine Summe über die ganze Tabelle mit einem einzelnen Namen. Für die Summe gibt es keinen einzelnen Kundennamen als Beschriftung.
Korrigiere die Abfrage passend zur Frage
Es gibt drei nützliche Korrekturen, jede mit einer anderen Bedeutung:
- Für eine Zeile pro Region entferne
customer:SELECT region, COUNT(*) FROM orders GROUP BY region;. - Für eine Zeile pro Region und Kunde gruppiere nach beiden:
SELECT region, customer, COUNT(*) FROM orders GROUP BY region, customer;. - Für die Anzahl der Kunden pro Region aggregiere die Namen:
SELECT region, COUNT(DISTINCT customer) AS customers FROM orders GROUP BY region;.
Die letzte Abfrage meldet zwei Kunden in East und einen in jeder anderen Regionsgruppe. Eine zusätzliche Spalte in GROUP BY kann die Detailebene des Berichts verändern. Wähle die Korrektur daher anhand der Frage und nicht nur anhand der Fehlermeldung.
Eine Gruppierungsspalte darf in SELECT fehlen. SELECT COUNT(*) FROM orders GROUP BY region; ist zulässig und gibt vier Anzahlen zurück: drei, zwei, zwei und eins, ohne garantierte Reihenfolge. Ohne ihre Regionsbezeichnungen sind diese Zahlen schwer zu verwenden.
Wende die Regel über SELECT hinaus an
Ein ORDER BY customer in einer gruppierten Abfrage hat bei einer Gruppierung allein nach Region dasselbe Problem: Welcher Kunde soll die Position von East bestimmen? Auch HAVING-Bedingungen in gruppierten Abfragen müssen eine ganze Gruppe beschreiben. Verwende dort gruppierte Spalten oder Aggregatausdrücke.
Erkenne nachgiebiges Datenbankverhalten
SQLite akzeptiert eine nicht aggregierte Spalte, also eine ausgewählte Spalte, die weder gruppiert noch aggregiert wird. Es nimmt einen Wert aus einer Eingabezeile der Gruppe. Ein scheinbar erfolgreiches Ergebnis wie 'Ana' neben East bedeutet nicht, dass Ana für jede Bestellung in dieser Region steht.
Bei genau einem eingebauten Aggregat MIN oder MAX nimmt SQLite Werte nicht aggregierter Spalten aus einer Zeile mit dem Extremwert. Bei gleichen Extremwerten und mehreren Aggregaten für Extremwerte ist ungewiss, welche Zeile ausgewählt wird. Diese Abkürzung ist datenbankspezifisch. Wenn du eine Bestellung mit einem Extrembetrag suchst, ist das Sortieren der ursprünglichen Zeilen klarer.
Der Standardmodus ONLY_FULL_GROUP_BY von MySQL lehnt nicht gruppierte Werte ab, die nicht durch die Gruppe bestimmt sind. ANY_VALUE(customer) erlaubt ausdrücklich einen beliebigen Wert, findet aber nicht den Kunden, der zu einer gewählten Summe gehört. SQL Server und Oracle lehnen gewöhnliche nicht gruppierte Spalten ebenfalls ab.
PostgreSQL und MySQL erkennen eine Ausnahme für Primärschlüssel: Die Gruppierung nach dem Primärschlüssel einer Tabelle identifiziert eine einzelne Zeile, sodass deren andere Spalten bestimmt sind. SELECT order_id, customer, SUM(amount) FROM orders GROUP BY order_id funktioniert in PostgreSQL. Alle angezeigten gewöhnlichen Spalten in GROUP BY aufzuführen, bleibt der übertragbare Ansatz.
Wichtige Erkenntnisse
- Jeder angezeigte Wert muss die ganze Gruppe beschreiben.
- Eine Spalte zu entfernen, zu gruppieren oder zu aggregieren, beantwortet unterschiedliche Fragen.
- Die Gruppierungsregel gilt auch für
HAVINGundORDER BYin gruppierten Abfragen. - Von SQLite akzeptierte nicht aggregierte Spalten können einen fehlerhaften Bericht verbergen.
- Ein gruppierter Primärschlüssel bestimmt die anderen Spalten seiner Zeile.
2.3 Nach mehreren Spalten und nach berechneten Werten gruppieren
Manche Berichte benötigen eine Kombination von Kategorien oder eine aus jeder Zeile berechnete Kategorie. SQL kann nach mehreren Spalten oder nach einem Ausdruck gruppieren. Entscheidend bleibt, wofür eine Ausgabezeile steht.
Gruppiere nach einer Kombination
GROUP BY region, customer fasst Zeilen nur zusammen, wenn beide Werte übereinstimmen. Führe für die Bestelltabelle aus:
SELECT region, customer, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY region, customer ORDER BY region, customer;
Die Ergebnisse sind East/Ana: zwei Bestellungen, 165; East/Dara: eine, 95; North/Chen: zwei, 350; West/Ben: zwei, 140; und NULL/Eli: eine, 30. Die beiden Ergebnisse für East ergeben zusammen die regionale Summe von 260.
Die Gruppierung nach customer, region bildet dieselben Kombinationen. Die Spaltenreihenfolge in GROUP BY sortiert die Ausgabe nicht. Das separate ORDER BY oben bestimmt die Anzeige, wobei die Standardposition von NULL von der jeweiligen Datenbank abhängt.
Es erscheinen nur Kombinationen, die in der Eingabemenge vorkommen. Es gibt keine Zeile West/Ana mit der Anzahl null. Die Gruppierung fasst vorhandene Zeilen zusammen; sie erzeugt nicht jede mögliche Paarung von Kategorienamen.
Ergänze Details nur bei Bedarf
Eine zusätzliche Spalte teilt eine Gruppe nur dann auf, wenn deren Zeilen in dieser Spalte unterschiedliche Werte enthalten. Die Gruppierung allein nach Kunde ergibt hier bereits fünf Gruppen. Mit Region sind es weiterhin fünf, weil jeder Kunde nur einen Regionswert hat. Ergänzt man order_date in einem regionalen Bericht, entstehen kleinere Gruppen für die einzelnen Daten und die beantwortete Frage ändert sich.
Gruppiere Datumswerte nach Jahr und Monat
Verwende in SQLite strftime('%Y-%m', order_date), um eine Bezeichnung wie '2026-02' zu erzeugen:
SELECT strftime('%Y-%m', order_date) AS month, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY strftime('%Y-%m', order_date) ORDER BY month;
Januar hat zwei Bestellungen mit zusammen 200, Februar drei mit zusammen 305 und März drei mit zusammen 275. Ersetze in PostgreSQL für eine DATE-Spalte beide Vorkommen von strftime('%Y-%m', order_date) durch to_char(order_date, 'YYYY-MM').
Eine Gruppierung allein nach der Monatsnummer fasst denselben Monat über mehrere Jahre hinweg zusammen. Januar 2025 und Januar 2026 würden eine Gruppe bilden. Bleibt das Jahr im Gruppierungsausdruck, bleiben die Kalendermonate getrennt.
Die Wiederholung des Ausdrucks in GROUP BY macht die Gruppierung ausdrücklich. SQLite, PostgreSQL und MySQL akzeptieren auch den Ausgabealias, etwa GROUP BY month; SQL Server akzeptiert dort keinen SELECT-Alias derselben Ebene.
Bilde Kategorien mit CASE
Ein CASE-Ausdruck kann jede Bestellung vor der Gruppierung beschriften:
SELECT CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END AS size, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END;
Die Kategorie large enthält 120, 200 und 150: drei Bestellungen mit zusammen 470. Die Kategorie small enthält fünf Bestellungen mit zusammen 310. Der Schwellenwert ist eingeschlossen, sodass ein Betrag von genau 100 zu 'large' gehört. Derselbe CASE-Ausdruck steht in der Anzeige und in der Gruppierung, sodass beide dieselbe Kategoriedefinition verwenden.
Wichtige Erkenntnisse
- Mehrere Gruppierungsspalten bestimmen Kombinationen, die in den Daten vorkommen.
- Eine zusätzliche Spalte teilt nur Gruppen auf, in denen diese Spalte unterschiedliche Werte enthält.
- Beziehe Jahr und Monat ein, um Kalendermonate getrennt zu halten.
- Verwende denselben Kategorieausdruck für die ausgewählte Beschriftung und die Gruppierung.
GROUP BYerzeugt keine fehlenden Kombinationen mit der Anzahl null.- Die Reihenfolge der Gruppierungsspalten steuert nicht die Ausgabereihenfolge.
3Gruppierte Ergebnisse mit HAVING filtern
Ein Filter kann die Zeilen einer Berechnung verändern oder entscheiden, welche fertigen Zusammenfassungen in einem Bericht erscheinen. Diese Entscheidungen beantworten unterschiedliche Fragen. Du verwendest HAVING, um Gruppen nach Anzahl, Summe oder Durchschnitt zu behalten, und kombinierst es anschließend mit WHERE, ohne die beabsichtigte Bedeutung zu verändern. Die logische Reihenfolge einer Abfrage hilft dir, jede Bedingung richtig zu platzieren und das Ergebnis vor der Ausführung von SQL vorherzusagen.
3.1 Nur die Gruppen behalten, die eine Bedingung erfüllen
HAVING prüft Gruppen, nachdem ihre Aggregate berechnet wurden. Verwende es für eine Anforderung wie „Regionen mit einem Gesamtumsatz über 200“. Die Bedingung beschreibt jede regionale Summe, nicht eine einzelne Bestellung.
Zuerst berechnen, dann Gruppen behalten
SELECT region, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY region HAVING SUM(amount) > 200;
Vor HAVING lauten die regionalen Summen East 260, North 350, West 140 und NULL 30. Die Bedingung behält East mit drei Bestellungen und North mit zwei. Sie entfernt die beiden anderen Ergebnisgruppen; sie entfernt keine ausgewählten Bestellungen innerhalb von East oder North.
Setze HAVING im geschriebenen SQL nach GROUP BY und vor ORDER BY. Die Sortierung wird dann auf die Gruppen angewendet, die die Bedingung erfüllt haben.
Filtere nach Kennzahlen, die du nicht anzeigst
SELECT region FROM orders GROUP BY region HAVING COUNT(*) >= 2; gibt East, North und West zurück. Die Datenbank kann die Zeilen einer Gruppe zählen, um zu entscheiden, ob sie die Bedingung erfüllt, ohne diese Anzahl anzuzeigen. HAVING und SELECT benötigen keine identischen Aggregatlisten.
Du kannst Gruppenbedingungen verknüpfen. HAVING COUNT(*) >= 2 AND AVG(amount) > 80 behält East und North. East hat drei Bestellungen und einen Durchschnitt von etwa 86,67; North hat zwei und einen Durchschnitt von 175. West hat genügend Bestellungen, aber sein Durchschnitt beträgt nur 70. Beide Prüfungen müssen erfüllt sein, weil sie mit AND verknüpft sind; OR würde das Erfüllen einer der beiden Prüfungen genügen lassen.
Finde wiederholte Werte
Gruppieren und Zählen findet auch Duplikate:
SELECT customer, COUNT(*) AS orders FROM orders GROUP BY customer HAVING COUNT(*) > 1;
Ana, Ben und Chen haben jeweils zwei Bestellungen und erfüllen die Bedingung. Dara und Eli haben jeweils eine und erfüllen sie nicht. Um wiederholte E-Mail-Werte in einer Kundentabelle zu finden, gruppiert dasselbe Muster nach email und behält Anzahlen über eins. Die Anzahl gibt an, wie viele Datensätze diesen Wert teilen.
Verwende den Ausdruck, den die Bedingung benötigt
Wiederhole das Aggregat in HAVING: HAVING SUM(amount) > 200. PostgreSQL und Standard-SQL erlauben den Ausgabealias total in dieser Bedingung auf derselben Ebene nicht, SQLite und MySQL dagegen schon. In einem späteren ORDER BY total DESC kann der Alias verwendet werden.
Ein angezeigter gerundeter Wert und der geprüfte Wert können sich unterscheiden. Der exakte Durchschnitt von East ist 260 geteilt durch drei. Wenn du ROUND(AVG(amount), 2) auswählst, aber HAVING AVG(amount) > 86.67 schreibst, wird East entfernt: Sein ungerundeter Durchschnitt liegt unter 86,67. North bleibt. Die Bedingung verwendet genau den Ausdruck, der in HAVING steht. Nur HAVING ROUND(AVG(amount), 2) ... würde den gerundeten Wert prüfen.
Filtere die einzelne Gesamtgruppe
HAVING kann auch ohne ausdrückliches GROUP BY arbeiten. SELECT COUNT(*) FROM orders HAVING COUNT(*) > 5; behandelt alle acht Bestellungen als eine Gruppe, erfüllt die Bedingung und gibt eine Zeile mit acht zurück. Ersetzt du die Bedingung durch COUNT(*) > 10, erhältst du keine Zeilen, keine Zeile mit null.
PostgreSQL unterstützt dieses Muster ebenso wie SQLite ab Version 3.39.0. In einer älteren SQLite-Installation benötigt eine Abfrage mit HAVING ein ausdrückliches GROUP BY.
Wichtige Erkenntnisse
HAVINGbehält oder entfernt fertig berechnete Gruppen.- Ein Aggregat in
HAVINGmuss nicht inSELECTerscheinen. - Verknüpfe Gruppenbedingungen mit
AND,ORundNOT. - Wiederhole für übertragbare Abfragen Aggregatausdrücke in
HAVING. - Eine Bedingung prüft ihren eigenen Ausdruck, der ungerundet sein kann.
3.2 Zwischen WHERE und HAVING wählen
Eine Bedingung gehört an die Stelle, an der das Beschriebene existiert. Einzelne Bestellungen existieren vor der Gruppierung. Eine regionale Summe existiert erst, nachdem die Bestellungen gruppiert und addiert wurden.
Verfolge die logische Reihenfolge
SQL wird in der Reihenfolge SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT geschrieben. Um das Ergebnis nachzuvollziehen, folge dieser logischen Reihenfolge:
FROMliefert die Zeilen.WHEREbehält passende Zeilen.GROUP BYbildet Gruppen, und Aggregate berechnen deren Kennzahlen.HAVINGbehält passende Gruppen.SELECTerzeugt die Ausgabewerte;DISTINCTentfernt auf Wunsch doppelte Ausgabezeilen.ORDER BYsortiert das Ergebnis, undLIMITbehält die gewünschte Anzahl von Zeilen.
Die Datenbank kann ihre interne Ausführung anders anordnen.
Setze jede Bedingung auf die passende Ebene
| Anforderung | Klausel |
|---|---|
Bestellungen mit amount >= 60 | WHERE |
| Bestellungen in einem bestimmten Datumsbereich | WHERE |
Regionen mit SUM(amount) > 200 | HAVING |
| Kunden mit mehr als einer Bestellung | HAVING COUNT(*) > 1 |
WHERE SUM(amount) > 200 schlägt fehl, weil die Summe beim Filtern der Zeilen noch nicht existiert. Eine Zeilenbedingung wie region = 'East' kann vor der Gruppierung entschieden werden und gehört in WHERE.
Gehe beide Filter durch
SELECT region, COUNT(*) AS orders, SUM(amount) AS total FROM orders WHERE amount >= 60 GROUP BY region HAVING SUM(amount) > 200;
Entferne zuerst die Bestellungen über 45 und 30. East enthält nun 120 und 95, North enthält 200 und 150 und West enthält 80 und 60. Berechne danach die Summen 215, 350 und 140. Behalte zuletzt Summen über 200. Die Ausgabe ist East mit zwei Bestellungen und 215 sowie North mit zwei und 350. Für die NULL-Region bleiben keine Zeilen übrig, sodass sie keine Gruppe bildet.
Verändere beim Verschieben eines Filters nicht die Frage
„Berechne für jede Region den Durchschnitt nur für Bestellungen ab 60“ verwendet WHERE amount >= 60. Der Durchschnitt von East beträgt aus 120 und 95 nun 107,5.
HAVING MIN(amount) >= 60 fragt nach Regionen, in denen jeder Betrag ohne NULL den Schwellenwert erreicht. East wird entfernt, weil sein Minimum 45 ist; North und West bleiben mit ihren ursprünglichen Bestellungen erhalten. Das Verschieben der Bedingung hat die Bedeutung verändert: Statt einzelne Bestellungen auszuwählen, werden ganze Regionen angenommen oder abgelehnt.
Für diesen regionalen Bericht ergibt region <> 'West' in WHERE oder HAVING dasselbe Ergebnis: East und North bleiben, und auch die NULL-Gruppe erfüllt den Vergleich nicht. WHERE formuliert die Zeileneinschränkung direkt und wendet sie vor der Gruppierung an. Um fehlende Regionen ebenfalls zu behalten, benötigt die Bedingung ein ausdrückliches OR region IS NULL.
SELECT-Aliase stehen in PostgreSQL in den früheren Klauseln WHERE und HAVING nicht zur Verfügung. SQLite erlaubt Aliase an mehr Stellen, aber das Ausschreiben der Eingabespalte oder des Ausdrucks macht die beabsichtigte Verarbeitungsstufe deutlich.
Wichtige Erkenntnisse
WHEREverändert die Eingaben der Aggregate;HAVINGfiltert Aggregatergebnisse.- Setze Bedingungen für Anzahl, Summe oder Durchschnitt einer Gruppe in
HAVING. - Verfolge beim Vorhersagen eines Ergebnisses die Zeilenfilterung vor der Gruppierung.
- Eine Prüfung des Gruppenminimums kann eine ganze Gruppe entfernen.
4Exakte und sinnvoll gerundete Ergebnisse berechnen
Eine Abfrage kann die richtigen Zeilen auswählen und dennoch den Nachkommateil ihres Ergebnisses verlieren. Zahlentypen steuern die Division und die Ergebnisse von Aggregaten, während die Rundung bestimmt, wie viele Stellen du anzeigst. Du erhältst Nachkommastellen während der Berechnung, wählst einen sinnvollen Umgang mit einem leeren Nenner und rundest nur die endgültige Kennzahl. Derselbe kurze Ausdruck kann sich je nach Datenbank unterschiedlich verhalten, daher wird jeder relevante Unterschied genannt.
4.1 Ganzzahlige Division bei Durchschnitten und Prozentwerten vermeiden
Beim Teilen zweier ganzzahliger Werte kann der Nachkommateil verloren gehen, bevor du das Ergebnis überhaupt anzeigst. Das ist wichtig, wenn du aus Summen und Anzahlen ein arithmetisches Mittel oder einen Prozentwert berechnest.
Sorge vor der Division für einen Dezimaloperanden
In SQLite und PostgreSQL gibt 7 / 2 3 zurück. Bei ganzzahliger Eingabe gibt SUM(quantity) / COUNT(*) für die Bestelltabelle 2 zurück: Bei 19 Artikeln geteilt durch acht Bestellungen geht der Nachkommateil verloren. PostgreSQLs SUM einer INTEGER-Spalte gibt BIGINT zurück, sodass hier weiterhin ganzzahlig dividiert wird.
Schreibe 1.0 * SUM(quantity) / COUNT(*), um in beiden Datenbank-Engines 2,375 zu erhalten. Die Multiplikation mit 1,0 erzeugt vor der Division einen Dezimaloperanden. SUM(quantity) / COUNT(*) * 1.0 ergibt 2,0, weil die Division den Nachkommateil bereits abgeschnitten hat. Operationen mit demselben Rang werden von links nach rechts ausgewertet.
Für diese Tabelle ergibt AVG(quantity) in SQLite und PostgreSQL direkt 2,375. Die von Hand geschriebene Formel ist wichtig, wenn du einen anderen Nenner oder einen Prozentwert benötigst.
Berechne einen Prozentwert
Drei der acht Bestellungen haben Beträge von mindestens 100. Die Anzahl dieser Bestellungen geteilt durch die Anzahl aller Bestellungen ergibt ihren Anteil. Multipliziere mit 100,0:
SELECT 100.0 * COUNT(CASE WHEN amount >= 100 THEN 1 END) / COUNT(*) AS pct_large FROM orders;
Das Ergebnis ist 37,5. Verwendest du stattdessen die ganze Zahl 100, ergibt sich in SQLite und bei ganzzahliger Division der Anzahlen in PostgreSQL 37. Nachträgliches Runden würde nur ändern, wie 37 angezeigt wird.
Eine Abfrage über die ganze Tabelle kann keine passenden Zeilen finden. NULLIF(COUNT(*), 0) gibt NULL zurück, wenn die Anzahl null ist, sodass 100.0 * COUNT(discount) / NULLIF(COUNT(*), 0) bei leerer Eingabemenge NULL zurückgibt. Ein ungeschützter Nenner von null löst in PostgreSQL einen Fehler aus; SQLite gibt NULL zurück. Ein NULL-Anteil kann klar für „keine Bestellungen zur Auswertung“ stehen.
Prüfe die Datenbank und den Eingabetyp
| Datenbank | Verhalten, auf das du achten musst |
|---|---|
| SQLite | Ganzzahlige Division schneidet den Nachkommateil ab; AVG gibt eine Gleitkommazahl zurück. |
| PostgreSQL | Ganzzahlige Division schneidet den Nachkommateil ab; AVG gibt bei ganzzahliger oder NUMERIC-Eingabe NUMERIC zurück. |
| SQL Server | Ganzzahlige Division schneidet den Nachkommateil ab; AVG gibt bei ganzzahliger Eingabe eine ganze Zahl zurück. |
| MySQL und Oracle | / erhält bei ganzzahligen Operanden den Nachkommateil des Ergebnisses. |
Verwende in SQL Server AVG(quantity * 1.0) oder wandle die Eingaben vor der Durchschnittsberechnung in DECIMAL um. In PostgreSQL gibt SUM einer BIGINT-Spalte NUMERIC zurück, sodass sich die Division nicht wie bei SUM einer INTEGER-Spalte verhalten muss. MySQL gibt für Summen ganzzahliger Eingaben DECIMAL zurück.
Auch eine explizite Typumwandlung kann den benötigten Dezimaloperanden erzeugen: Verwende CAST(SUM(quantity) AS REAL) in SQLite oder CAST(SUM(quantity) AS NUMERIC) in PostgreSQL. Die Umwandlung in NUMERIC kann in SQLite eine ganze Zahl erhalten, sodass diese Umwandlung allein keine Dezimaldivision sicherstellt.
Unterscheide exakte Dezimalzahlen von Näherungswerten
Gleitkommatypen speichern binäre Näherungswerte. PostgreSQLs NUMERIC und DECIMAL unterstützen exakte Dezimalwerte; Additionen mit Gleitkommazahlen können kleine Abweichungen wie 0,30000000000000004 anzeigen. SQLites NUMERIC-Affinität bietet keine exakte Dezimalspeicherung. Für exakte Geldsummen speichere dort ganzzahlige Centbeträge, addiere sie und teile zur Anzeige durch 100,0.
Wichtige Erkenntnisse
- Erzeuge einen Dezimaloperanden, bevor du ganzzahlige Summen oder Anzahlen dividierst.
- Eine Multiplikation nach der ganzzahligen Division kann verlorene Stellen nicht zurückbringen.
- Verwende
NULLIF, um einen Nenner von null zu behandeln. - Die Ergebnistypen von Aggregaten hängen sowohl von der Datenbank-Engine als auch vom Eingabetyp ab.
- Die
NUMERIC-Affinität von SQLite bietet keine exakte Dezimalspeicherung. - SQL Server benötigt Dezimaleingaben, damit der Durchschnitt ganzer Zahlen einen Nachkommateil haben kann.
4.2 Aggregierte Ergebnisse runden
Runden bestimmt, wie viele Stellen ein Ergebnis zeigt. Runde erst im letzten Schritt, damit die Darstellung die berechnete Kennzahl nicht verändert.
Runde ein Aggregatergebnis
ROUND(x, n) rundet auf n Stellen nach dem Komma. ROUND(x) rundet auf eine ganze Zahl. Zum Beispiel ist ROUND(3.14159, 2) gleich 3,14.
SELECT region, ROUND(AVG(amount), 2) AS avg_amount FROM orders GROUP BY region; ergibt East 86,67, North 175, West 70 und für die NULL-Region 30. SQLite zeigt möglicherweise 175,0 an, während das NUMERIC-Ergebnis von PostgreSQL 175,00 anzeigt. Beide stehen für dieselbe Zahl. Eine Zahl zu runden und eine Textbeschriftung mit fester Breite zu formatieren, sind unterschiedliche Aufgaben.
Runde nach dem Addieren oder Mitteln
Addiere bei drei Gebühren von 0,44 zuerst zu 1,32 und runde dann auf eine Nachkommastelle, um 1,3 zu erhalten. ROUND(SUM(fee), 1) folgt dieser Reihenfolge. SUM(ROUND(fee, 1)) rundet jede Gebühr auf 0,4 und addiert sie dann, was 1,2 ergibt. Das frühe Runden hat die Summe verändert.
Ebenso ergibt ROUND(100 * 1 / 3, 1) in SQLite und PostgreSQL 33,0, weil die ganzzahlige Division bereits 33 erzeugt hat. ROUND(100.0 * 1 / 3, 1) erhält den Nachkommateil und ergibt 33,3. Wähle den Berechnungstyp vor dem Runden.
Gerundete Anteile ergeben zusammen möglicherweise nicht 100 %. Drei gleiche Anteile können jeweils als 33,3 % angezeigt werden und zusammen 99,9 % ergeben. Die zugrunde liegenden Anteile ergeben weiterhin das Ganze. Berechnest du einen beliebigen Anteil neu, um die angezeigte Summe zu erzwingen, änderst du die Bedeutung dieser angezeigten Zahl.
Verwende einen unterstützten Eingabetyp
PostgreSQL unterstützt ROUND(value, n) mit zwei Argumenten für NUMERIC. Wenn temp vom Typ DOUBLE PRECISION ist, schreibe ROUND(CAST(AVG(temp) AS NUMERIC), 2). Der Durchschnitt von 20,5, 21,25 und 19,0 ist 20,25, und die Typumwandlung ermöglicht das Runden mit zwei Argumenten. Bei ganzzahligem amount ist der Durchschnitt in PostgreSQL bereits NUMERIC, sodass keine Typumwandlung nötig ist.
Bei exakten NUMERIC-Werten rundet PostgreSQL Rundungsgrenzfälle von null weg: 2,5 wird zu 3 und -2,5 wird zu -3. SQLite ergibt bei diesen Beispielen ebenfalls 3,0 und -3,0. Das Runden von Gleitkommazahlen in PostgreSQL hängt von der Plattform ab; häufig wird zur nächsten geraden Zahl gerundet. Durch binäre Näherung kann eine Dezimalzahl auch knapp unter einem vorgesehenen Rundungsgrenzfall liegen. Verwende einen bestimmten Gleitkomma-Grenzfall nicht als allgemeine Regel für exakte Dezimalarithmetik.
Beachte zwei weitere Dialektunterschiede
PostgreSQL, MySQL, SQL Server und Oracle verwenden eine negative Anzahl von Dezimalstellen, um links vom Komma zu runden. ROUND(1234.5, -2) ergibt 1200. SQLite behandelt ein negatives zweites Argument als null und ergibt 1235,0. Um in SQLite auf Hunderter zu runden, verwende ROUND(x / 100.0) * 100.
Auch die Umwandlung in eine ganze Zahl ist datenbankspezifisch: SQLite schneidet den Nachkommateil ab, sodass 2,9 zu 2 wird; PostgreSQL rundet den Wert auf 3. Verwende ROUND, wenn gerundet werden soll. PostgreSQLs TRUNC(x, n) schneidet dagegen Stellen ab: TRUNC(2.97, 1) ist 2,9, während das Runden auf eine Nachkommastelle 3,0 ergibt.
Wichtige Erkenntnisse
- Runde das Aggregatergebnis nach Abschluss seiner Berechnung.
- Runden kann eine vorherige ganzzahlige Division nicht korrigieren.
- Gerundete Prozentwerte können zusammen 99,9 % oder 100,1 % ergeben.
- Wandle einen Gleitkommadurchschnitt in PostgreSQL für
ROUNDmit zwei Argumenten inNUMERICum. - Negative Rundungsstellen und Umwandlungen in ganze Zahlen unterscheiden sich zwischen Datenbanken.
5Geschäftliche Fragen mit zusammenfassenden Abfragen beantworten
Geschäftsberichte benötigen oft mehrere Kennzahlen für dieselbe Grundgesamtheit: alle Bestellungen, große Bestellungen und den Anteil der großen Bestellungen. Bedingte Aggregation hält diese Kennzahlen nebeneinander. Anschließend erstellst du aus einer Frage einen vollständigen Bericht, prüfst Summen und fehlende Kategorien und verwendest einen zweiten Aggregationsschritt, wenn sich die Frage auf Kunden oder andere Gruppen statt auf einzelne Bestellungen bezieht.
5.1 Mit CASE bedingt zählen und summieren
Bedingte Aggregation ermöglicht unterschiedliche Beiträge zu verschiedenen Kennzahlen, während dieselben Zeilen insgesamt erhalten bleiben. Ein CASE-Ausdruck entscheidet, was jede Zeile zu einer Anzahl oder Summe beiträgt.
Zähle passende Zeilen
COUNT(CASE WHEN amount >= 100 THEN 1 END) zählt Bestellungen ab 100. Der Ausdruck gibt bei einem Treffer 1 und für andere Zeilen NULL zurück, weil er kein ELSE hat. COUNT überspringt diese NULL-Werte, sodass in der Bestelltabelle drei Treffer bleiben.
SUM(CASE WHEN amount >= 100 THEN 1 ELSE 0 END) zählt Treffer, indem Einsen und Nullen addiert werden. Bei vorhandenen Eingabezeilen ergibt sich dieselbe Anzahl. Für COUNT(CASE WHEN amount >= 100 THEN 1 ELSE 0 END) gilt das nicht: Sowohl 1 als auch 0 sind nicht NULL, sodass alle acht Bestellungen gezählt werden.
Addiere passende Beträge
Gib für eine bedingte Summe den Betrag selbst zurück:
SELECT region, COUNT(*) AS orders, COUNT(CASE WHEN amount >= 100 THEN 1 END) AS large_orders, SUM(CASE WHEN amount >= 100 THEN amount ELSE 0 END) AS large_total FROM orders GROUP BY region;
East hat drei Bestellungen, eine große Bestellung und eine Summe großer Bestellungen von 120. North hat zwei Bestellungen, beide groß, mit zusammen 350. West hat zwei Bestellungen, keine großen Bestellungen und eine Summe großer Bestellungen von null. Die NULL-Regionsgruppe hat eine Bestellung und für beide Kennzahlen zu großen Bestellungen jeweils null.
Die Ausgabe behält West, weil seine Eingabezeilen weiterhin existieren. Ein zusätzliches WHERE amount >= 100 würde die Zeilen von West vor der Gruppierung entfernen, sodass West verschwände. Dieser Filter würde außerdem bewirken, dass COUNT(*) nur große Bestellungen zählt, wodurch der Vergleich mit allen Bestellungen verloren ginge.
Verwende den richtigen Nenner
Berechne innerhalb jeder Region den Prozentsatz großer Bestellungen mit ROUND(100.0 * COUNT(CASE WHEN amount >= 100 THEN 1 END) / COUNT(*), 1) AS pct_large. East ergibt 33,3, North 100,0, West 0,0 und die NULL-Gruppe 0,0. Jeder Nenner ist die Bestellanzahl der jeweiligen Gruppe, nicht die Anzahl von acht für die ganze Tabelle.
Schütze bei einem nicht gruppierten Bericht, der keine Zeilen enthalten kann, den Nenner mit NULLIF(COUNT(*), 0). Eine Zählung bei leerer Eingabemenge ergibt null, aber für den Prozentwert einer leeren Grundgesamtheit gibt es keinen Nenner.
Erstelle mehrere Kategoriespalten
Ein einzelnes Ergebnis kann eine Anzahl pro Region zeigen:
SELECT COUNT(CASE WHEN region = 'East' THEN 1 END) AS east, COUNT(CASE WHEN region = 'West' THEN 1 END) AS west, COUNT(CASE WHEN region = 'North' THEN 1 END) AS north FROM orders;
Die Anzahlen sind drei, zwei und zwei. Elis Bestellung gehört zu keiner dieser Prüfungen auf eine benannte Region. Ergänze COUNT(CASE WHEN region IS NULL THEN 1 END), um die eine Bestellung ohne Region zu zählen. Der Vergleich einer NULL-Region mit einem Namen ergibt keine wahre Bedingung.
Erkenne alternative Schreibweisen
PostgreSQL und SQLite ab Version 3.30.0 unterstützen COUNT(*) FILTER (WHERE amount >= 100). Der Filter gilt für dieses Aggregat, sodass ein benachbartes ungefiltertes COUNT(*) weiterhin alle Bestellungen zählt. MySQL und SQL Server unterstützen diese FILTER-Schreibweise für Aggregate nicht; die CASE-Form funktioniert auf beiden.
SQLite und MySQL erlauben auch SUM(amount >= 100), weil Vergleiche numerische Wahrheitswerte erzeugen. PostgreSQL lehnt SUM für boolesche Werte ab. Verwende die CASE-Form, wenn eine Abfrage auf diesen Datenbank-Engines funktionieren soll.
Wichtige Erkenntnisse
- Setze Bedingungen in Aggregate, um Kennzahlen für verschiedene Teilmengen zusammenzuhalten.
COUNT(CASE ... THEN 1 END)überspringt Zeilen ohne Treffer.ELSE 0funktioniert für eine bedingte Summe, bewirkt aber bei einer bedingten Zählung, dass auch Zeilen ohne Treffer zählen.- Ein Prozentanteil in der Gruppe verwendet die Grundgesamtheit dieser Gruppe als Nenner.
- Eine
FILTER-Klausel für ein Aggregat verändert nur dessen Eingaben. - Verwende
IS NULL, um fehlende Kategorien gesondert zu zählen.
5.2 Aus einer Frage eine zusammenfassende Abfrage erstellen und prüfen
Eine zusammenfassende Abfrage beginnt mit einer Frage zu einer Grundgesamtheit auf einer bestimmten Detailebene. Übersetze diese Entscheidungen, bevor du SQL schreibst, und prüfe dann, ob die Ausgabe weiterhin die ursprüngliche Frage beantwortet.
Erstelle den Bericht der Reihe nach
Frag dich: „Wie viele Bestellungen wurden in jedem Monat des Jahres 2026 mit mindestens drei Bestellungen aufgegeben, und wie hoch war der durchschnittliche Betrag auf zwei Nachkommastellen?“
- Die Kennzahlen sind
COUNT(*)undAVG(amount). - Die Granularität, also die Bedeutung einer Ergebniszeile, ist ein Kalendermonat.
- Die Zeilenbedingung behält Datumswerte aus 2026.
- Die Gruppenbedingung verlangt mindestens drei Bestellungen.
- Die Ausgabe soll nach Monat sortiert und der Durchschnitt für die Anzeige gerundet werden.
In SQLite:
SELECT strftime('%Y-%m', order_date) AS month, COUNT(*) AS orders, ROUND(AVG(amount), 2) AS avg_amount FROM orders WHERE order_date >= '2026-01-01' AND order_date < '2027-01-01' GROUP BY strftime('%Y-%m', order_date) HAVING COUNT(*) >= 3 ORDER BY month;
Ersetze für PostgreSQL-Datumswerte den Monatsausdruck an beiden Stellen durch to_char(order_date, 'YYYY-MM'). Der Datumsbereich schließt den Beginn von 2026 ein und den Beginn von 2027 aus.
Januar hat zwei Bestellungen und erfüllt die Gruppenbedingung nicht. Februar hat drei Bestellungen mit zusammen 305 und einem Durchschnitt von 101,67. März hat drei mit zusammen 275 und einem Durchschnitt von 91,67. Auf die verbleibenden Gruppen entfallen sechs Bestellungen, nicht acht, weil HAVING den Januar entfernt hat.
Prüfe, bevor du Gruppen herausfilterst
Führe den Bericht zuerst ohne HAVING aus. Die Anzahlen aller Gruppen sollten zusammen der Zeilenanzahl unter demselben WHERE-Filter entsprechen und die Summen zusammen der nicht gruppierten Summe. Hier ergeben diese Prüfungen acht und 780. Vergleiche die Summen der beibehaltenen Gruppen nicht mit der gesamten Eingabemenge, nachdem Gruppen ausgeschlossen wurden.
Suche nach einer NULL-Gruppe, prüfe die Reihenfolge der Ergebnisse und berechne eine Gruppe nach, indem du die Rohtabelle filterst. Für East sollte WHERE region = 'East' drei Bestellungen mit zusammen 260 ergeben. Eine Abweichung kann eine zusätzliche Gruppierungsspalte, einen falsch platzierten Zeilenfilter oder einen Ausdruck aufdecken, der zu NULL wurde.
Unterscheide eine durchschnittliche Bestellung von einem durchschnittlichen Kunden
AVG(amount) beträgt 97,5 pro Bestellung. Die durchschnittlichen Ausgaben pro Kunde beziehen sich auf eine andere Einheit: Die fünf Kundensummen sind 165, 140, 350, 95 und 30. Ihr Durchschnitt ist 156.
Berechne das in zwei Stufen:
SELECT AVG(total) AS avg_customer_total FROM (SELECT customer, SUM(amount) AS total FROM orders GROUP BY customer) AS per_customer;
Die innere Abfrage erzeugt eine Zeile pro Kunde. Die äußere Abfrage bildet den Durchschnitt dieser Zeilen, sodass jeder Kunde einen Beitrag leistet. Sind alle Kunden benannt, ergibt 1.0 * SUM(amount) / COUNT(DISTINCT customer) dieselbe Zahl 156. Bei unterschiedlichen Bestellanzahlen ist die Durchschnittsbildung über Bestellbeträge eine andere Berechnung.
Fasse die Gruppen selbst zusammen
Um Kunden mit mehr als einer Bestellung zu zählen, liste sie zunächst auf und zähle dann ihre Zeilen:
SELECT COUNT(*) FROM (SELECT customer FROM orders GROUP BY customer HAVING COUNT(*) > 1) AS repeat_customers;
Die Antwort ist drei. Die direkte Verschachtelung von Aggregaten wie in MAX(AVG(amount)) auf einer Abfrageebene schlägt in SQLite und PostgreSQL fehl. Um die Region mit dem höchsten Durchschnitt zu finden, sortiere die gruppierten Durchschnitte: ORDER BY AVG(amount) DESC LIMIT 1 gibt North mit 175 zurück. Oracle unterstützt auch verschachtelte Gruppenfunktionen, aber eine separate Abfrageebene macht die beiden Berechnungen ausdrücklich. Prüfe gleiche Werte, wenn ein Bericht nach dem höchsten Ergebnis fragt.
Wichtige Erkenntnisse
- Leite Kennzahlen, Granularität, Zeilenbedingungen und Gruppenbedingungen aus der Frage ab.
- Prüfe Gruppenanzahlen und -summen, bevor du Gruppen mit
HAVINGentfernst. - Ein Durchschnitt pro Kunde benötigt Kundensummen als Eingabewerte.
- Verwende eine innere gruppierte Abfrage und ein äußeres Aggregat, um Gruppen zusammenzufassen.
SQL-Aggregation: Beispiele
1Aus Bestellzeilen zuverlässige zusammenfassende Zahlen gewinnen
13 Schritte
- 1EinführungLies die Frage für den Bericht
Eine Führungskraft möchte eine Bestellsumme, eine Kundenanzahl und einen durchschnittlichen Rabatt. Jede Größe klingt nach einer einfachen Zahl, verwendet die Eingabe aber anders. Jede ist ein Aggregat, das viele Zeilen in einen Wert überführt, und eine falsche Wahl ergibt eine irreführende Zahl. Wir bilden diese Kennzahlen aus den acht Bestellungen: zuerst Beträge zusammenfassen, dann die Zählweise wählen und anschließend entscheiden, wie NULL den Durchschnitt verändert. Frag dich immer wieder, was eine Eingabezeile zum Ergebnis beiträgt.
- 2ErklärungFasse die Beträge zusammen
Ein Aggregat fasst Werte aus vielen Zeilen zu einem Ergebnis zusammen.
SUM(amount)addiert die Beträge,AVG(amount)ermittelt ihren Durchschnitt undMIN(amount)undMAX(amount)bestimmen die Extremwerte. OhneGROUP BYbilden alle passenden Bestellungen eine Gruppe. Du kannst mehrere Aggregate zusammen auswählen, weil jedes dieselbe Gruppe von Eingabezeilen beschreibt. - 3BeispielBerechne eine vollständige Zusammenfassung
Die Bestellbeträge sind 120, 80, 45, 200, 60, 95, 150 und 30. Sie ergeben zusammen 780. Teilt man diese Summe durch acht, ergibt sich ein Durchschnitt von 97,5; der kleinste Wert ist 30 und der größte 200.
SELECT SUM(amount) AS total, AVG(amount) AS mean_amount, MIN(amount) AS low, MAX(amount) AS high FROM orders;Die Ausgabe ist eine Zeile mit vier beschrifteten Kennzahlen.
- 4BeispielWähle die Eingabe vor dem Addieren
Frage nun nur nach East.
WHERE region = 'East'behält die Beträge 120, 45 und 95, bevor das Aggregat berechnet wird.SELECT SUM(amount) AS total FROM orders WHERE region = 'East';Die Ausgabe ist 260. Die anderen Regionen tragen nichts bei, weil ihre Bestellungen die Zeilenbedingung nicht erfüllen. Ein Filter auf Eingabezeilen verändert die Summe selbst, nicht nur ihre angezeigte Beschriftung.
- 5HerausforderungHalte eine Menge mit ihrem Preis zusammen
Eine Verkaufstabelle hat zwei Zeilen: Menge 4 zum Stückpreis 6 und Menge 2 zum Stückpreis 9. Was gibt
SUM(quantity * unit_price)zurück, und warum ist die Multiplikation der beiden Summen etwas anderes?---reveal---
Die Zeilenumsätze sind 24 und 18, die Summe ist also 42. Die Multiplikation der Summen ergibt sechs mal 15, also 90, weil dabei nicht mehr jede Menge dem Preis ihrer eigenen Zeile zugeordnet wird.
- 6ErklärungZähle Datensätze oder Kunden
Die Bestellungen nennen Ana, Ben, Ana, Chen, Ben, Dara, Chen und Eli.
COUNT(customer)zählt acht erfasste Namen einschließlich wiederholter Vorkommen.COUNT(DISTINCT customer)zählt fünf verschiedene Namen.Die Formulierung entscheidet, was passt: Eine Bestellanzahl benötigt Zeilen, eine Kundenanzahl unterschiedliche Kunden. Gleiche Namen auf separaten Bestellungen sind erwartete Wiederholungen, keine zusätzlichen Kunden.
- 7BeispielZähle die fehlende Kategorie
Die Regionsspalte hat acht Zeilen, aber nur sieben erfasste Werte.
COUNT(*)ist acht,COUNT(region)ist sieben undCOUNT(DISTINCT region)ist drei.Zieht man die Anzahl erfasster Werte von der Zeilenanzahl ab, ergibt sich eine fehlende Region. Beachte, dass eine Liste unterschiedlicher Regionen auch eine NULL-Zeile enthalten würde; die Zählung unterschiedlicher Werte ignoriert dieses NULL, statt es als vierte benannte Region zu behandeln.
- 8HerausforderungWähle die richtige Zählweise
Eine Gutscheinspalte enthält NULL, 0, 8, 8 und 0. Welche Werte geben
COUNT(*),COUNT(coupon)undCOUNT(DISTINCT coupon)in dieser Reihenfolge zurück?---reveal---
Sie geben fünf, vier und zwei zurück. Es gibt fünf Zeilen, vier erfasste Werte und zwei unterschiedliche erfasste Werte, 0 und 8. Erfasste Nullwerte zählen; NULL geht in keine der beiden Spaltenzählungen ein.
- 9ErklärungLass eine unbekannte Punktzahl weg
Betrachte die Punktzahlen 80, NULL, 70 und 90. Die erfassten Punktzahlen ergeben zusammen 240.
AVG(score)teilt durch die drei erfassten Punktzahlen und gibt 80 zurück.Es teilt nicht durch alle vier Zeilen: Eine fehlende Punktzahl ist keine bekannte Null. Steht der fehlende Wert für eine versäumte Prüfung, die mit null Punkten bewertet werden soll, ändert sich die beabsichtigte Berechnung zu
AVG(COALESCE(score, 0)), was 60 ergibt. - 10BeispielSetze den Ersatzwert an der richtigen Stelle ein
Bei vier Bestellungen fehlt der Rabatt. In
SUM(amount - discount)wird jeder dieser Zeilenausdrücke zu NULL, sodass nur die anderen vier beitragen. Ihre Nettobeträge ergeben zusammen 345.Wenn fehlend bedeutet, dass kein Rabatt gewährt wurde, verwende
SUM(amount - COALESCE(discount, 0)). Dann tragen alle acht Bestellungen bei und die Summe beträgt 750.COALESCEum die fertige Summe kann ausgelassene Zeilenbeiträge nicht zurückbringen. - 11HerausforderungBehandle eine Gruppe ohne bekannte Werte
Eine Abfrage behält drei Zeilen, deren Beträge alle NULL sind. Was geben
COUNT(*),COUNT(amount)undSUM(amount)zurück?---reveal---
Sie geben drei, null und NULL zurück. Es gibt Zeilen, aber keine erfassten Beträge zum Zählen oder Addieren. Eine leere Eingabemenge würde ebenfalls eine NULL-Summe ergeben, aber ihre Zeilenanzahl wäre null. Verwende
COALESCE(SUM(amount), 0)nur, wenn der Bericht diese fehlende Summe als null anzeigen soll. - 12HerausforderungPrüfe eine Berechnung und ihre Grundgesamtheit
Vier Leistungsdatensätze haben Beträge von 20, 30, 40 und 50 sowie Gutschriften von 2, NULL, 0 und NULL. Eine fehlende Gutschrift bedeutet, dass keine Gutschrift vorliegt. Welchen Nettogesamtbetrag und welche Anzahl erfasster Gutschriften sollte der Bericht zeigen?
---reveal---
Verwende
SUM(charge - COALESCE(credit, 0))für einen Nettogesamtbetrag von 138 undCOUNT(credit)für zwei erfasste Gutschriften. Die Gutschrift von null zählt als erfasst; das Ersetzen von NULL innerhalb der Summe erhält alle vier Beträge. - 13ZusammenfassungBeziehe die Kennzahl auf ihre Eingaben
Wähle das Aggregat anhand der Frage und verfolge dann die Werte, die eingehen. Zählungen unterscheiden Zeilen, erfasste Einträge und unterschiedliche Einträge. Prüfe bei Durchschnitten und Rechnungen pro Zeile, was NULL entfernt und ob eine Ersetzung eine tatsächliche Bedeutung hat. Wenn ein Ergebnis überraschend aussieht, untersuche die verbleibenden Zeilen und ihre Beiträge, bevor du das SQL änderst.
2Erstelle einen Bericht auf der richtigen Detailebene
14 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungEntscheide, wofür eine Ergebniszeile steht
- 2ErklärungFasse Zeilen nach Region zusammen
- 3BeispielHalte die NULL-Gruppe sichtbar
- 4TippSortiere, bevor du die ersten Zeilen behältst
- 5HerausforderungSage voraus, wie viele Gruppen bleiben
- 6ErklärungErkläre, warum ein Name mehrdeutig ist
- 7BeispielKorrigiere den Bericht anhand seiner Frage
- 8TippErkenne ein Ergebnis aus nachgiebiger Verarbeitung
- 9HerausforderungWähle eine sinnvolle Korrektur
- 10BeispielTeile eine Gruppe nach einem zweiten Wert auf
- 11ErklärungErstelle eine Kalendermonatsbezeichnung
- 12HerausforderungFinde den Gruppierungsausdruck
- 13HerausforderungPrüfe Granularität und Beschriftungen des Berichts
- 14ZusammenfassungLies jede Zeile als eine Gruppe
3Filter vor oder nach der Aggregation platzieren
10 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungTrenne Grundgesamtheit und Auswahl
- 2ErklärungPrüfe die fertig berechnete Gruppe
- 3BeispielVerwende eine Anzahl, ohne sie anzuzeigen
- 4HerausforderungPrüfe den tatsächlich verglichenen Wert
- 5ErklärungVerfolge die logischen Stufen des Ergebnisses
- 6BeispielEntferne zuerst kleine Bestellungen
- 7BeispielEntferne dann kleine Gruppensummen
- 8HerausforderungErkenne eine veränderte Frage
- 9HerausforderungKombiniere Zeilen- und Gruppeneinschränkungen
- 10ZusammenfassungOrdne die Bedingung ihrer Stufe zu
4Nachkommateile erhalten und das Endergebnis runden
11 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungHalte Berechnung und Anzeige getrennt
- 2BeispielFinde, wo der Nachkommateil verschwindet
- 3ErklärungFühre die Dezimalzahl früh ein
- 4TippSichere einen leeren Nenner ab
- 5HerausforderungKorrigiere einen Prozentwertausdruck
- 6ErklärungRunde den fertig berechneten Durchschnitt
- 7BeispielSieh, wie frühes Runden eine Summe verändert
- 8HerausforderungPrüfe einen Dialektunterschied
- 9VerbindungWähle den Typ für exakte Beträge
- 10HerausforderungPrüfe den Typ vor dem Runden
- 11ZusammenfassungVerfolge die Zahl durch jede Stufe
5Eine geschäftliche Zusammenfassung erstellen und prüfen
13 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungHalte alle und ausgewählte Bestellungen zusammen
- 2ErklärungLass Zeilen ohne Treffer NULL beitragen
- 3BeispielHalte die vollständige Gruppe verfügbar
- 4BeispielAddiere den Betrag oder addiere eins
- 5HerausforderungErhalte den Nenner für eine Teilmenge
- 6ErklärungÜbersetze die geschäftliche Formulierung
- 7BeispielErstelle das monatliche Ergebnis
- 8TippPrüfe, bevor du Gruppen ausblendest
- 9ErklärungÄndere die Eingabeeinheit für einen Durchschnitt
- 10BeispielLies die beiden Abfrageebenen
- 11HerausforderungWähle die richtige Einheit für den Durchschnitt
- 12HerausforderungZähle nur passende Kundengruppen
- 13ZusammenfassungPrüfe Grundgesamtheit und Granularität
SQL-Aggregation: Übungsaufgaben
Set 1: Anzahlen, Gruppen und Berechnungen lesen10 Übungsfragen
Frage 1 von 10
SUM(distance) zurück?Antwort zeigenAntwort ausblenden
SUM addiert die drei Entfernungen und ergibt 71. Die größte Entfernung, 35, wäre das Ergebnis von MAX(distance), während ein Durchschnitt die Gesamtentfernung durch drei teilen würde; keines von beiden beantwortet die Frage nach einer Summe.Frage 2 von 10
COUNT(CASE WHEN status = 'closed' THEN 1 ELSE 0 END) zurück?Antwort zeigenAntwort ausblenden
Frage 3 von 10
AVG(delay) zurück?Antwort zeigenAntwort ausblenden
AVG teilt durch ihre Anzahl von drei, was acht Minuten ergibt. Eine Division durch alle vier Zeilen würde sechs Minuten ergeben und die unbekannte Verspätung damit durch null ersetzen, obwohl keine solche Messung erfasst wurde.Frage 4 von 10
SELECT department, COUNT(*) FROM shifts GROUP BY department zurück?Antwort zeigenAntwort ausblenden
Frage 5 von 10
FROM parts GROUP BY category?Antwort zeigenAntwort ausblenden
COUNT(DISTINCT supplier) fasst alle erfassten Lieferantenwerte einer Kategorie zu einer Anzahl unterschiedlicher Lieferanten zusammen. Ein gewöhnlicher Lieferantenwert ist mehrdeutig, weil die Kategorie mehrere Lieferanten haben kann. COUNT(supplier) würde Datensätze mit einem Lieferanten einschließlich wiederholter Vorkommen zählen.Frage 6 von 10
paid_on mit Datensätzen von 2024 bis einschließlich 2026. Welcher Gruppierungsausdruck hält jeden Kalendermonat getrennt?Antwort zeigenAntwort ausblenden
Frage 7 von 10
HAVING SUM(amount) > 200?Antwort zeigenAntwort ausblenden
>= 200 würde Grün bestehen lassen. HAVING wendet diesen Vergleich auf jede fertig berechnete Teamsumme an und behält oder entfernt somit jedes gesamte Teamergebnis.Frage 8 von 10
ORDER BY supplier. Kategorien haben mehrere Lieferanten. Wie kann sie die Kategorien mit den höchsten Kosten zuerst anzeigen, ohne ihre Granularität zu verändern?Antwort zeigenAntwort ausblenden
Frage 9 von 10
SUM(quantity) / COUNT(*) * 1.0 zurück?Antwort zeigenAntwort ausblenden
1.0 * SUM(quantity) / COUNT(*) ein.Frage 10 von 10
ROUND(SUM(fee), 1) aus, behält die Gesamtgruppe aber nur mit HAVING SUM(fee) >= 0.8. Welches Ergebnis gibt sie zurück?Antwort zeigenAntwort ausblenden
Set 2: Grundgesamtheit und Detailebene des Berichts wählen10 Übungsfragen
Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.
Frage 1 von 10
COUNT(priority) zurück?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 2 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
MIN(delivery_date) und MAX(delivery_date) in dieser Reihenfolge zurück?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
SELECT COUNT(*) FROM (SELECT DISTINCT city, agent FROM visits) AS pairs zurück?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
SUM(cost - credit) und die beabsichtigten gesamten Nettokosten in dieser Reihenfolge?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
ORDER BY total DESC, customer ASC LIMIT 2, wenn die Namen alphabetisch sortiert werden?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
ROUND(SUM(fee), 1) und SUM(ROUND(fee, 1)) in dieser Reihenfolge, wenn du winzige Anzeigeabweichungen durch Gleitkommazahlen ignorierst?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
SELECT training FROM roster GROUP BY training HAVING COUNT(*) >= 3 zurück?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 10 von 10
WHERE amount >= 60 GROUP BY team HAVING AVG(amount) > 80?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Set 3: Fehlende Werte, Typen und Gruppen kombinieren10 Übungsfragen
Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.
Frage 1 von 10
SELECT 17 / 5 in SQLite zurück?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 2 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
SELECT SUM(quantity * price) FROM stock WHERE department = 'A' zurück?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
COUNT(DISTINCT region) zurück?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
jobs passen zu state = 'queued'. Was gibt SELECT team, COALESCE(SUM(hours), 0) FROM jobs WHERE state = 'queued' GROUP BY team zurück?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
WHERE area IS NOT NULL GROUP BY area die Gruppenanzahlen?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 10 von 10
CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END. Wie viele Gruppen entstehen?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Set 4: Vollständige Berichte untersuchen und fertigstellen10 Übungsfragen
Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.
Frage 1 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 2 von 10
WHERE amount >= 30 mit der Gruppierung aller Zeilen unter Verwendung von HAVING MIN(amount) >= 30. Welche Durchschnitte erscheinen?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
temperature vom Typ DOUBLE PRECISION. Wie rundest du den Durchschnitt auf zwei Nachkommastellen?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
COUNT(*) FILTER (WHERE paid = 1) neben COUNT(*) in einer gruppierten Abfrage ohne WHERE-Klausel. Was schränkt der Filter ein?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
COUNT(*), COUNT(value) und MAX(value) in dieser Reihenfolge?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
WHERE zone <> 'West'. Welche Zonengruppen können bleiben?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 10 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Hängst du bei deiner eigenen Aufgabe fest? Hausaufgabenhilfe
Schlüsselbegriffe
A
abgeleitete Tabelle
FROM verwendet wird, sodass eine zweite Abfrage die von der ersten erzeugten Zeilen zusammenfassen kann.Abgleich
HAVING aus, damit ausgeschlossene Gruppen keinen Unterschied zwischen Bericht und Eingabesumme erklären.abschließendes Runden
Abschneiden
TRUNC, und SQLite schneidet bei der Umwandlung in eine ganze Zahl ab.TRUNC(2.97, 1) ergibt in PostgreSQL 2,9, während ROUND(2.97, 1) für diese exakte Dezimalzahl 3,0 ergibt.Aggregatausdruck
SUM(amount - discount) wertet die Subtraktion pro Zeile aus, bevor die Ergebnisse ohne NULL addiert werden.Aggregatfunktion
SUM(amount), um viele Bestellbeträge zu einer Summe für den ausgewählten Zeitraum zusammenzufassen.AVG
AVG(amount) ergibt 97,5 für acht Bestellungen, deren Beträge zusammen 780 ergeben, und misst den durchschnittlichen Bestellbetrag.B
bedingte Aggregation
bedingte Summe
CASE-Ausdruck, der für nicht passende Zeilen null zurückgibt.CASE den passenden Betrag selbst zurück; die Rückgabe von 1 würde stattdessen Bestellungen zählen.bedingte Zählung
COUNT NULL zurückgeben.COUNT(CASE WHEN amount >= 100 THEN 1 END) zählt große Bestellungen und überspringt die NULL-Ergebnisse nicht passender Zeilen.C
CASE-Kategorie
CASE-Ausdruck zugewiesene Bezeichnung, die zur Grundlage eines gruppierten Berichts werden kann.amount >= 100 ordnet eine Bestellung über genau 100 der Kategorie „large“ zu.CAST
REAL ermöglicht in SQLite eine Dezimaldivision, während eine Umwandlung in NUMERIC einen ganzzahligen Wert als ganze Zahl belassen kann.COALESCE
COALESCE(SUM(amount), 0) zeigt null an, wenn eine leere Eingabemenge andernfalls eine NULL-Summe ergeben würde.COUNT(*)
COUNT(*) von acht, selbst wenn für eine Bestellung keine Region erfasst ist.COUNT(DISTINCT Spalte)
COUNT(DISTINCT customer) für die Anzahl benannter Kunden, selbst wenn einige mehrere Bestellungen aufgeben.COUNT(Spalte)
COUNT(discount) zählt eine Bestellung mit Rabatt null mit, lässt aber eine Bestellung mit Rabatt NULL aus.D
Dezimaloperand
DISTINCT
SUM(DISTINCT quantity) addiert jeden Mengenwert einmal, sodass wiederholte tatsächliche Verkäufe in der Summe fehlen können.Duplikaterkennung
HAVING COUNT(*) > 1 findet Kunden mit wiederholten Bestelldatensätzen.Durchschnitt pro Kunde
E
eindeutige Wertekombination
Eingabe aus lauter NULL-Werten
COUNT(x) null ist.COUNT(*) vier und COUNT(discount) null, wenn ein Filter nur diese Bestellungen auswählt.F
FILTER-Klausel für Aggregate
funktionale Abhängigkeit
G
ganzzahlige Division
Gleitkommazahl
DOUBLE PRECISION kann in PostgreSQL 0,30000000000000004 anzeigen, wo exakte Dezimalarithmetik 0,3 ergibt.Granularität
GROUP BY
GROUP BY region ermöglicht es, in derselben Abfrage eine separate Bestellanzahl und Betragssumme für jede Region zu berechnen.Gruppenbedingung
Gruppierung nach mehreren Spalten
Gruppierungsausdruck
CASE zugewiesene Kategorie.Gruppierungsregel
Gruppierungsspalte
H
HAVING
HAVING SUM(amount) > 200 behält Regionen anhand ihrer Summe, ohne kleine Bestellungen aus verbleibenden Gruppen zu entfernen.I
IS NULL
WHERE region IS NULL wählt Bestellungen aus, deren Region nicht erfasst wurde, etwa eine Bestellung eines Kunden namens Eli.J
Jahr-Monat-Schlüssel
K
Kennzahl
L
leere Eingabemenge
WHERE-Bedingung keine passenden Datensätze findet.logische Verarbeitungsreihenfolge
WHERE vor GROUP BY erklärt, warum das Entfernen kleiner Bestellungen den späteren Durchschnitt einer Region verändert.M
MIN und MAX
MIN(order_date) findet das früheste Datum, wenn die Spalte Datumswerte oder einheitlich formatierten ISO-Datumstext enthält.N
nachrangiges Sortierkriterium
ORDER BY total DESC, customer gibt gleichen Kundensummen eine stabile Reihenfolge, bevor eine Begrenzung angewendet wird.nicht aggregierte Spalte
NULL
amount - discount NULL ist, sodass SUM den berechneten Wert dieser Zeile überspringt.NULL-Gruppe
NULLIF
NULLIF(COUNT(*), 0) macht den Nenner eines leeren Berichts zu NULL und vermeidet in PostgreSQL einen Fehler durch Division durch null.NUMERIC und DECIMAL
O
ONLY_FULL_GROUP_BY
ORDER BY
ORDER BY total DESC listet nach der Berechnung jeder Gruppe die größten Gruppensummen zuerst auf.P
Prozentanteil in der Gruppe
R
ROUND
ROUND(AVG(amount), 2) rundet den fertig berechneten Durchschnitt auf zwei Stellen und lässt die vorherige Berechnung unverändert.Rundungsdifferenz
Rundungsgrenzfall
NUMERIC-Werte von 2,5 auf 3 und von -2,5 auf -3, beide Grenzfälle also von null weg.S
SELECT-Alias
ORDER BY verwendet werden kann und dessen Verwendung an anderen Stellen vom Dialekt abhängt.ORDER BY total, benötigt aber in einem HAVING derselben Ebene den ausgeschriebenen Aggregatausdruck.Sortierfolge
MIN-Abfrage gleich bleiben.SUM
SUM(quantity * unit_price) summiert Zeilenumsätze, nachdem jede Menge mit ihrem passenden Preis multipliziert wurde.V
Vergleich mit dem ungerundeten Wert
HAVING AVG(amount) >= 86.67 dennoch nicht erfüllen, wenn sein exakter Wert kleiner ist.W
WHERE
WHERE, bevor er Monatssummen berechnet.Z
Zeilenbedingung
amount >= 60 kann eine Bestellung aus East behalten und eine andere entfernen, bevor eine regionale Zusammenfassung existiert.Über diese Einheit
Erstelle deine eigenen Lernmaterialien
Mach aus deinen Notizen, Folien und Dokumenten Lernleitfäden, Übungsfragen, Karteikarten und 6 weitere Tools.