Zum Inhalt
wannacode

GROUP BY: ein Bericht nach Gruppen

Kurz gesagt: GROUP BY legt Zeilen mit demselben Wert in eine Gruppe, damit COUNT, SUM oder AVG für jede Gruppe einzeln berechnet werden.

Problem

Das Dashboard des Lagers

Das Lager will ein Dashboard: wie viele Bestellungen neu sind, wie viele bezahlt, wie viele verschickt. Mit COUNT(*) und WHERE status = 'new' bräuchtest du fünf Abfragen, eine für jeden Status. Und wenn morgen ein sechster Status auftaucht, zeigt der Bericht ihn nicht.

Du brauchst eine Abfrage, die die Status selbst findet und jeden zählt.

Die Idee

GROUP BY

GROUP BY Spalte legt die Zeilen mit demselben Wert in der Spalte in eine Gruppe. Die Aggregatfunktion wird für jede Gruppe einzeln berechnet:

SQLDatenbank: Shop

60 Bestellungen, fünf Gruppen, fünf Zeilen. Jede Gruppe ergibt eine Zeile.

Die Kunden nach Stadt:

SQLDatenbank: Shop

Boris hat keine Stadt und steht in einer eigenen Gruppe mit city = NULL. Für GROUP BY sind wie für DISTINCT alle NULL eine Gruppe.

Wie aus einer Gruppe eine Zeile wird, sieht man an wenigen Zeilen leichter. Die letzten drei Bestellungen sind sechs Zeilen in order_items:

SQLDatenbank: Shop

SELECT order_id, COUNT(*) AS lines, ROUND(SUM(quantity * unit_price), 2) AS total
FROM order_items
WHERE order_id >= 58
GROUP BY order_id;
Schritt für Schritt, in Worten
  1. 6 Zeilen aus order_items: die Produkte in den Bestellungen 58, 59 und 60.
  2. GROUP BY order_id: Jede Zeile kommt in die Gruppe ihrer order_id.
  3. 3 verschiedene order_id, 3 Gruppen. In jeder sind 2 Zeilen.
  4. Die Gruppe von 58 wird eine Zeile: COUNT(*) ist 2, und SUM(quantity * unit_price) ist 1 × 1,20 + 4 × 1,90 = 8,80 €.
  5. Die Gruppe von 59: 2 Zeilen, 3 × 2,50 + 2 × 3,20 = 13,90 €.
  6. Die Gruppe von 60: 2 Zeilen, 2 × 1,20 + 4 × 2,90 = 14,00 €.
  7. 6 Zeilen gingen hinein, 3 kamen heraus: eine für jede Gruppe.

Die Abfrage aus der Szene. ROUND(…, 2) rundet die Summe auf den Cent:

SQLDatenbank: Shop

Probier es aus

Bestellungen pro Kunde

Wie viele Bestellungen hat jeder Kunde aufgegeben? Zeige customer_id und die Anzahl.

SQLDatenbank: Shop

Die Idee

Der Wert jeder Bestellung

In order_items belegt eine Bestellung mehrere Zeilen, eine für jedes Produkt. Eine Gruppe nach order_id bringt die Positionen einer Bestellung zusammen:

SQLDatenbank: Shop

Jetzt ist jede Bestellung eine Zeile: wie viele Produkte sie hat und wie viel sie wert ist.

Eine Gruppe kann auch nach zwei Spalten gebildet werden. Dann enthält eine Gruppe die Zeilen, in denen beide Werte gleich sind. Die Bestellungen von Kunde 1 nach Status:

SQLDatenbank: Shop

Eine Gruppe kann auch nach einem berechneten Wert gebildet werden. strftime('%Y-%m', ordered_at) nimmt Jahr und Monat aus dem Datum, und die Bestellungen werden nach Monat gruppiert:

SQLDatenbank: Shop

Sieh es dir an

Die Spalte, die nicht in der Gruppe steht

Die Bestellungen pro Kunde, und daneben der Status. Sieht vernünftig aus:

SQLDatenbank: Shop
1. Die Abfrage zeigte „8 | cancelled | 3“. Was bedeutet das?

Die Bestellungen von Kunde 8 zeigen, was los ist:

SQLDatenbank: Shop

Drei Bestellungen, drei verschiedene Status. Die Gruppe ist eine Zeile, und sie hat Platz für einen Wert. SQLite sagt nichts und nimmt den Status aus einer der Zeilen. Aus welcher, ist nicht versprochen.

Die Regel: Jede Spalte im SELECT steht entweder in GROUP BY oder in einem Aggregat (COUNT, SUM, MIN …). PostgreSQL und SQL Server melden für so eine Abfrage einen Fehler, und MySQL mit seinen Standardeinstellungen seit Version 5.7 ebenso. SQLite akzeptiert sie und zeigt etwas, das wie eine Antwort aussieht.

Wenn du die Status willst, gruppiere nach beiden Spalten: GROUP BY customer_id, status.

Genauer, für Neugierige

SQLite hat eine Eigenheit, die in der Dokumentation steht: Wenn die Abfrage genau ein MIN oder MAX hat, kommt die freie Spalte aus der Zeile mit dem kleinsten oder größten Wert. SELECT customer_id, MAX(ordered_at), id FROM orders GROUP BY customer_id liefert die Nummer der jüngsten Bestellung. Das gibt es nur in SQLite. Andere Datenbanken lehnen es ab, und im Modul über Unterabfragen sehen wir, wie es überall geht.

Probier es aus

Die Bestseller

Welche fünf Produkte haben sich am häufigsten verkauft? Zeige product_id und die Stückzahl in einer Spalte namens sold, den Bestseller zuerst.

SQLDatenbank: Shop

Übung

Zwei Berichte

1. Wie viele Produkte und wie viele Stück auf Lager gibt es in jeder Kategorie?

Zeige category_id, die Anzahl der Produkte und die Summe ihres Lagerbestands.

SQLDatenbank: Shop

2. Die Buchhaltung will die Anzahl der Bestellungen für jeden Monat 2026, nach Monat sortiert.

Zeige den Monat (Jahr-Monat) und die Anzahl der Bestellungen für jeden Monat 2026, in der Reihenfolge der Monate.

SQLDatenbank: Shop

Test

Teste dich

1. Wie viele Zeilen liefert SELECT status, COUNT(*) FROM orders GROUP BY status?
2. Boris hat keine Stadt. Wo steht er in SELECT city, COUNT(*) FROM customers GROUP BY city?
3. Was ergibt GROUP BY customer_id, status?
4. Was ist im SELECT einer Abfrage mit GROUP BY order_id sicher?

Erstellt von Ivo Gergov im Rahmen der Kampagne von Evo Tech für zugängliche Programmierausbildung ·