Eine Pivot-Tabelle macht aus Zeilen Spalten: eine Zeile pro Gruppe und eine Spalte für jeden Wert eines anderen Felds, etwa eine Spalte pro Quartal. In SQL baust du sie mit CASE innerhalb einer Aggregatfunktion wie SUM, gruppiert nach dem, was jede Zeile darstellen soll. Die Beispiele funktionieren in PostgreSQL, MySQL, SQLite und SQL Server.
So erstellst du eine Pivot-Tabelle in SQL
Schreib eine Aggregatfunktion pro Ausgabespalte. Das CASE darin lässt nur die Zeilen durch, die zu dieser Spalte gehören, und GROUP BY liefert eine Zeile pro Gruppe:
SELECT
row_column,
SUM(CASE WHEN pivot_column = 'value 1' THEN amount ELSE 0 END) AS value_1,
SUM(CASE WHEN pivot_column = 'value 2' THEN amount ELSE 0 END) AS value_2
FROM table_name
GROUP BY row_column;
Hier bekommt jedes Produkt eine Zeile, mit seinen Stückzahlen pro Quartal nebeneinander:
-- Input: sales
-- product | quarter | units
-- ---------+---------+------
-- Keyboard | Q1 | 120
-- Keyboard | Q2 | 95
-- Monitor | Q1 | 40
-- Monitor | Q2 | 55
-- Mouse | Q2 | 210
SELECT
product,
SUM(CASE WHEN quarter = 'Q1' THEN units ELSE 0 END) AS q1,
SUM(CASE WHEN quarter = 'Q2' THEN units ELSE 0 END) AS q2
FROM sales
GROUP BY product
ORDER BY product;
-- Output:
-- product | q1 | q2
-- ---------+-----+----
-- Keyboard | 120 | 95
-- Monitor | 40 | 55
-- Mouse | 0 | 210
Wichtige Regeln
-
Du benennst jede Spalte selbst. SQL kann keine Spalten aus den Daten erzeugen, ein drittes Quartal braucht also eine dritte
CASE-Zeile. Wenn sich die Liste der Werte ständig ändert, bau die Abfrage in deinem Anwendungscode zusammen. -
ELSE 0ist nur fürSUMund Zählungen gedacht. Es macht aus einer fehlenden Kombination 0 statt NULL. BeiAVG,MINoderMAXlässt duELSEweg, sonst zählen die Nullen als echte Werte:
-- Input: the sales table above
SELECT
product,
ROUND(AVG(CASE WHEN quarter = 'Q1' THEN units ELSE 0 END), 1) AS q1_else_0,
ROUND(AVG(CASE WHEN quarter = 'Q1' THEN units END), 1) AS q1_no_else
FROM sales
GROUP BY product
ORDER BY product;
-- Output:
-- product | q1_else_0 | q1_no_else
-- ---------+-----------+-----------
-- Keyboard | 60.0 | 120.0
-- Monitor | 20.0 | 40.0
-- Mouse | 0.0 | NULL
Alternative Syntax
Dir begegnen auch FILTER in PostgreSQL und SQLite sowie der PIVOT-Operator in SQL Server. Beide lassen eine fehlende Kombination als NULL statt 0 stehen:
-- Input: the sales table above
-- PostgreSQL and SQLite
SELECT
product,
SUM(units) FILTER (WHERE quarter = 'Q1') AS q1,
SUM(units) FILTER (WHERE quarter = 'Q2') AS q2
FROM sales
GROUP BY product
ORDER BY product;
-- SQL Server
SELECT product, [Q1] AS q1, [Q2] AS q2
FROM (SELECT product, quarter, units FROM sales) AS src
PIVOT (SUM(units) FOR quarter IN ([Q1], [Q2])) AS p
ORDER BY product;
-- Output:
-- product | q1 | q2
-- ---------+------+----
-- Keyboard | 120 | 95
-- Monitor | 40 | 55
-- Mouse | NULL | 210
In MySQL-Code siehst du oft SUM(IF(quarter = 'Q1', units, 0)), eine kürzere Schreibweise der CASE-Variante. Die PostgreSQL-Erweiterung tablefunc bietet außerdem eine crosstab()-Funktion; siehe Pivot-Tabellen in PostgreSQL mit crosstab() erstellen.
Wann solltest du eine Pivot-Tabelle verwenden?
Pivotiere, wenn eine Liste von Zeilen als Raster leichter zu lesen wäre. Das sind die typischen Gründe.
Eine Kennzahl direkt vergleichen
Stell die Werte, die du vergleichen willst (Tage, Quartale, Regionen), in einer Zeile nebeneinander, statt sie über eine lange Liste zu verteilen.
Mehrere Kennzahlen pro Spalte zeigen
Jede Ausgabespalte ist ein eigenes Aggregat, du kannst sie also kombinieren: Sessions und Seitenaufrufe pro Gerät oder Bestellungen und Umsatz pro Kanal.
Zeilen pro Kategorie zählen
Um zu zählen statt zu summieren, summierst du 1 für jede passende Zeile oder nutzt COUNT(CASE WHEN ... THEN 1 END): COUNT überspringt die NULLs, die die anderen Zeilen erzeugen. So bekommst du Aufgaben pro Status oder Tickets pro Priorität.
Key-Value-Zeilen in Spalten umwandeln
Einstellungen und Produktattribute werden oft als eine Zeile pro Name und Wert gespeichert. Pivotieren mit MAX(CASE ...) liefert eine Zeile pro Element mit einer Spalte pro Attribut. MAX funktioniert auch mit Text und wählt den einzigen Wert in jeder Gruppe.
Praxisbeispiele für Pivot-Tabellen in SQL
Durchschnittliche App-Bewertung pro Plattform
Lass ELSE beim Durchschnitt weg, damit eine App ohne Bewertungen auf einer Plattform NULL statt eines irreführenden Werts zeigt:
-- Input: reviews
-- app | platform | rating
-- ---------+----------+-------
-- Budgetly | iOS | 5
-- Budgetly | iOS | 4
-- Budgetly | Android | 3
-- FitTrack | Android | 4
-- FitTrack | Android | 5
-- In SQL Server, AVG of an integer column drops the decimals: use rating * 1.0
SELECT
app,
ROUND(AVG(CASE WHEN platform = 'iOS' THEN rating END), 1) AS ios,
ROUND(AVG(CASE WHEN platform = 'Android' THEN rating END), 1) AS android
FROM reviews
GROUP BY app
ORDER BY app;
-- Output:
-- app | ios | android
-- ---------+------+--------
-- Budgetly | 4.5 | 3.0
-- FitTrack | NULL | 4.5
Bestellungen und Umsatz pro Kanal und Region
Zwei Kennzahlen pro Kanal, eine Bestellanzahl und eine Summe:
-- Input: orders
-- id | region | channel | amount
-- ---+--------+---------+-------
-- 1 | North | web | 120.00
-- 2 | North | store | 80.00
-- 3 | North | web | 45.50
-- 4 | South | store | 210.00
-- 5 | South | store | 64.00
SELECT
region,
COUNT(CASE WHEN channel = 'web' THEN 1 END) AS web_orders,
SUM(CASE WHEN channel = 'web' THEN amount ELSE 0 END) AS web_sales,
COUNT(CASE WHEN channel = 'store' THEN 1 END) AS store_orders,
SUM(CASE WHEN channel = 'store' THEN amount ELSE 0 END) AS store_sales
FROM orders
GROUP BY region
ORDER BY region;
-- Output:
-- region | web_orders | web_sales | store_orders | store_sales
-- -------+------------+-----------+--------------+------------
-- North | 2 | 165.50 | 1 | 80.00
-- South | 0 | 0 | 2 | 274.00
Support-Tickets pro Agent nach Priorität
Eine Zählung pro Priorität plus eine Gesamtzahl. COUNT(*) zählt weiterhin jede Zeile der Gruppe:
-- Input: tickets
-- id | agent | priority
-- ---+-------+---------
-- 1 | Priya | urgent
-- 2 | Priya | normal
-- 3 | Marco | normal
-- 4 | Priya | normal
-- 5 | Marco | low
SELECT
agent,
COUNT(CASE WHEN priority = 'low' THEN 1 END) AS low,
COUNT(CASE WHEN priority = 'normal' THEN 1 END) AS normal,
COUNT(CASE WHEN priority = 'urgent' THEN 1 END) AS urgent,
COUNT(*) AS total
FROM tickets
GROUP BY agent
ORDER BY agent;
-- Output:
-- agent | low | normal | urgent | total
-- ------+-----+--------+--------+------
-- Marco | 1 | 1 | 0 | 2
-- Priya | 0 | 2 | 1 | 3
Eine Zeile mit Einstellungen pro User
Jede Einstellung wird als Name und Wert gespeichert. Ein User, der eine Einstellung nie gesetzt hat, bekommt in dieser Spalte NULL:
-- Input: user_settings
-- user_id | setting | value
-- --------+----------+--------------
-- 1 | theme | dark
-- 1 | language | en
-- 2 | language | de
-- 2 | timezone | Europe/Berlin
-- 3 | theme | light
SELECT
user_id,
MAX(CASE WHEN setting = 'theme' THEN value END) AS theme,
MAX(CASE WHEN setting = 'language' THEN value END) AS language,
MAX(CASE WHEN setting = 'timezone' THEN value END) AS timezone
FROM user_settings
GROUP BY user_id
ORDER BY user_id;
-- Output:
-- user_id | theme | language | timezone
-- --------+-------+----------+--------------
-- 1 | dark | en | NULL
-- 2 | NULL | de | Europe/Berlin
-- 3 | light | NULL | NULL
Weiterführende Artikel zu Pivot-Tabellen
In diesem Blog:
-
Pivotieren in PostgreSQL:
CASEundcrosstab()in PostgreSQL -
Pivot-Tabellen in PostgreSQL mit crosstab() erstellen: die Erweiterung
tablefuncim Detail - Leitfaden zum SQL-CASE-Statement: die Bedingungen in jeder Pivot-Spalte
- Leitfaden zu SQL GROUP BY: Zeilen gruppieren, bevor du sie pivotierst
Offizielle Dokumentation:
- PostgreSQL: Aggregatausdrücke und FILTER und crosstab()
- MySQL: CASE-Operator
- SQLite: Aggregatfunktionen und FILTER
- SQL Server: PIVOT und UNPIVOT
Beekeeper Studio ist eine kostenlose & quelloffene Datenbank-GUI
Das beste SQL-Abfrage- & Editor-Tool, das ich je benutzt habe. Es bietet alles, was ich zum Verwalten meiner Datenbank brauche. - ⭐⭐⭐⭐⭐ Mit
Beekeeper Studio ist schnell, intuitiv und einfach zu bedienen. Beekeeper unterstützt jede Menge Datenbanken und läuft hervorragend auf Windows, Mac und Linux.
Was User über Beekeeper Studio sagen
„Beekeeper Studio hat meinen alten SQL-Workflow komplett ersetzt. Es ist schnell, intuitiv und macht die Arbeit mit Datenbanken wieder zum Vergnügen.“
„Ich habe viele Datenbank-GUIs ausprobiert, aber Beekeeper findet die perfekte Balance zwischen Funktionsumfang und Einfachheit. Es funktioniert einfach.“