Conditional Aggregation: KPI-Reports mit CASE WHEN und FILTER bauen
AI generated
SELECT
JOIN
SQL · Conditional Aggregation · Reporting · KPI
Conditional Aggregation
KPI-Reports mit CASE WHEN und FILTER in einer Abfrage

Conditional Aggregation kombiniert CASE WHEN oder die FILTER-Klausel mit Aggregatfunktionen und berechnet dadurch mehrere bedingte Kennzahlen in einem einzigen Durchlauf über die Tabelle, statt für jede Kennzahl eine eigene Abfrage zu schreiben. Dieser Artikel zeigt, wie Conditional Aggregation Dashboards und Reports schneller, wartbarer und übersichtlicher macht, und welche Fallstricke bei NULL-Werten und Datentypen typischerweise auftreten.

14 Min. Lesezeit CASE WHEN · FILTER · SUM · COUNT · Reporting ANSI SQL · PostgreSQL · MySQL · SQL Server

1. Was Conditional Aggregation löst und warum sie wichtig ist

Conditional Aggregation bezeichnet die Technik, eine Bedingung direkt in eine Aggregatfunktion einzubauen, statt die Tabelle mehrfach zu filtern und die Ergebnisse anschließend im Anwendungscode zusammenzuführen. Der klassische Anwendungsfall ist ein Dashboard, das für eine Bestellliste gleichzeitig die Anzahl offener, versendeter und stornierter Bestellungen anzeigen soll. Ohne Conditional Aggregation müsste man drei separate Abfragen schreiben, jede mit einer eigenen WHERE-Bedingung, und die Ergebnisse anschließend manuell zusammenführen.

Mit Conditional Aggregation entsteht stattdessen eine einzige Abfrage, die alle drei Kennzahlen als eigene Spalten in derselben Ergebniszeile zurückgibt. Der Datenbankserver liest die Tabelle dafür nur einmal, statt sie dreimal zu scannen, was gerade bei großen Faktentabellen einen spürbaren Performance-Unterschied macht. Conditional Aggregation ist damit nicht nur eine Frage der Lesbarkeit, sondern eine direkte Optimierungstechnik für Reporting-Abfragen mit mehreren Kennzahlen.

Dieser Artikel zeigt beide gängigen Varianten von Conditional Aggregation, das klassische CASE-WHEN-Muster und die modernere FILTER-Klausel, erklärt typische NULL-Fallstricke und zeigt, wie sich Prozentanteile und Quoten direkt aus bedingt gezählten Werten berechnen lassen, ohne zusätzliche Abfragen oder Anwendungslogik.

2. Das Grundmuster: CASE WHEN innerhalb von Aggregatfunktionen

Das Grundmuster der Conditional Aggregation mit CASE WHEN funktioniert, indem ein CASE-Ausdruck innerhalb der Aggregatfunktion entscheidet, welcher Wert pro Zeile in die Berechnung eingeht. Für eine Zählung lautet das Muster COUNT(CASE WHEN bedingung THEN 1 END), wobei END ohne ELSE automatisch NULL für alle Zeilen liefert, die die Bedingung nicht erfüllen, und COUNT NULL-Werte bekanntlich ignoriert. Für eine Summe lautet das entsprechende Muster SUM(CASE WHEN bedingung THEN betrag ELSE 0 END), wobei hier ein explizites ELSE 0 nötig ist, damit SUM eine Zahl statt NULL zurückgibt, sobald keine Zeile die Bedingung erfüllt.

Der Unterschied zwischen COUNT(CASE WHEN...) und SUM(CASE WHEN...) bei Conditional Aggregation liegt also im ELSE-Zweig: Bei COUNT genügt THEN 1 ohne ELSE, weil NULL ignoriert wird. Bei SUM sollte man ELSE 0 immer explizit angeben, sonst kann eine Gruppe ohne passende Zeilen NULL statt 0 liefern, was nachgelagerte Berechnungen wie Prozentwerte oder weitere Summen verfälscht. Diese kleine, aber wichtige Unterscheidung ist einer der häufigsten Anfängerfehler bei Conditional Aggregation.


-- Conditional aggregation with CASE WHEN: multiple KPIs in one pass
SELECT
    DATE_TRUNC('month', order_date) AS month,
    COUNT(CASE WHEN status = 'open'      THEN 1 END)              AS open_orders,
    COUNT(CASE WHEN status = 'shipped'   THEN 1 END)              AS shipped_orders,
    COUNT(CASE WHEN status = 'cancelled' THEN 1 END)              AS cancelled_orders,
    SUM(CASE WHEN status = 'shipped'     THEN total_amount ELSE 0 END) AS shipped_revenue
FROM orders
GROUP BY DATE_TRUNC('month', order_date)
ORDER BY month;

3. Die FILTER-Klausel als moderne Alternative

Der SQL-Standard definiert seit SQL:2003 die FILTER-Klausel als saubere Alternative zu CASE WHEN bei Conditional Aggregation. Die Syntax lautet AGGREGATFUNKTION(ausdruck) FILTER (WHERE bedingung), wobei die Bedingung ausschließlich steuert, welche Zeilen in die jeweilige Aggregatfunktion einfließen, ohne den eigentlichen Ausdruck durch einen CASE-Block zu verschachteln. PostgreSQL unterstützt FILTER seit Version 9.4 vollständig, während MySQL und ältere SQL-Server-Versionen die Klausel bislang nicht kennen und weiterhin auf CASE WHEN angewiesen sind.

Der Vorteil von FILTER gegenüber CASE WHEN bei Conditional Aggregation liegt in der Klarheit: Die Bedingung steht direkt neben der Aggregatfunktion, statt in einem verschachtelten Ausdruck versteckt zu sein, und der Aggregatfunktion selbst muss kein künstlicher ELSE-Zweig für NULL oder 0 mitgegeben werden. Für COUNT(*) FILTER (WHERE status = 'shipped') etwa entfällt die sonst nötige CASE-Konstruktion komplett, was den Code deutlich lesbarer macht, besonders wenn viele Bedingungen in einer Abfrage kombiniert werden.


-- Conditional aggregation with the FILTER clause (PostgreSQL, SQL:2003 standard)
SELECT
    DATE_TRUNC('month', order_date) AS month,
    COUNT(*) FILTER (WHERE status = 'open')      AS open_orders,
    COUNT(*) FILTER (WHERE status = 'shipped')   AS shipped_orders,
    COUNT(*) FILTER (WHERE status = 'cancelled') AS cancelled_orders,
    SUM(total_amount) FILTER (WHERE status = 'shipped') AS shipped_revenue
FROM orders
GROUP BY DATE_TRUNC('month', order_date)
ORDER BY month;

4. Mehrere Kennzahlen nebeneinander in einer einzigen Zeile

Der eigentliche Mehrwert von Conditional Aggregation zeigt sich, sobald ein Report nicht nur drei, sondern zehn oder mehr Kennzahlen aus derselben Faktentabelle berechnen soll. Ein typisches Beispiel ist ein Vertriebsreport, der pro Region gleichzeitig Umsatz, Anzahl Bestellungen, Anzahl Neukunden, durchschnittlichen Bestellwert und Retourenquote in einer einzigen Ergebniszeile ausweisen soll. Jede dieser Kennzahlen bekommt eine eigene, unabhängige Bedingung, alle nebeneinander in derselben SELECT-Liste.

Ohne Conditional Aggregation müsste man diese zehn Kennzahlen entweder über zehn separate Abfragen mit anschließendem JOIN auf einen gemeinsamen Schlüssel zusammenführen, oder über zehn Subqueries in derselben Abfrage, was jeweils zu zehn unabhängigen Scans der Faktentabelle führt. Conditional Aggregation reduziert das auf genau einen Scan, unabhängig davon, wie viele Kennzahlen in der SELECT-Liste stehen, solange sie auf derselben Gruppierungsebene berechnet werden können.


-- Ten KPIs from one fact table scan using conditional aggregation
SELECT
    region,
    COUNT(*)                                              AS total_orders,
    COUNT(*) FILTER (WHERE is_new_customer)               AS new_customer_orders,
    SUM(total_amount)                                     AS total_revenue,
    ROUND(AVG(total_amount), 2)                           AS avg_order_value,
    COUNT(*) FILTER (WHERE returned)                      AS returned_orders,
    ROUND(
        100.0 * COUNT(*) FILTER (WHERE returned) / NULLIF(COUNT(*), 0),
        2
    )                                                      AS return_rate_pct
FROM orders
GROUP BY region
ORDER BY total_revenue DESC;

5. NULL-Fallstricke bei Conditional Aggregation vermeiden

Ein häufiger Fehler bei Conditional Aggregation mit CASE WHEN entsteht, wenn die geprüfte Spalte selbst NULL enthalten kann. Ein Ausdruck wie CASE WHEN status = 'shipped' THEN 1 END liefert bei status IS NULL weder wahr noch falsch, sondern unbekannt, wodurch die betroffene Zeile weder in den THEN- noch in einen ungewollten ELSE-Zweig fällt, sondern schlicht NULL wird und von COUNT ignoriert wird. Das ist in den meisten Fällen erwünscht, muss aber bewusst geprüft werden, wenn NULL-Status-Werte in der Fachlichkeit eine eigene Bedeutung haben.

Ein zweiter Fallstrick betrifft SUM ohne ELSE: SUM(CASE WHEN bedingung THEN betrag END) liefert NULL statt 0, sobald keine Zeile der Gruppe die Bedingung erfüllt, was in nachgelagerten Berechnungen wie Prozentanteilen zu unerwarteten NULL-Werten führen kann. Bei Conditional Aggregation mit der FILTER-Klausel tritt dasselbe Problem auf, weil COUNT(*) FILTER und SUM(spalte) FILTER dem normalen NULL-Verhalten der jeweiligen Aggregatfunktion folgen. Ein COALESCE um das Gesamtergebnis herum schafft in beiden Varianten Abhilfe, wenn eine Zahl statt NULL fachlich erwartet wird.


-- NULL pitfalls in conditional aggregation, and how to guard against them
SELECT
    customer_id,
    -- Without ELSE: NULL when no row matches, not 0
    SUM(CASE WHEN category = 'electronics' THEN amount END) AS electronics_raw,
    -- With ELSE 0: always a number, safe for further math
    SUM(CASE WHEN category = 'electronics' THEN amount ELSE 0 END) AS electronics_safe,
    -- FILTER follows the same NULL behavior as the underlying aggregate
    COALESCE(SUM(amount) FILTER (WHERE category = 'electronics'), 0) AS electronics_filter_safe
FROM purchases
GROUP BY customer_id;

6. Conditional Aggregation kombiniert mit GROUP BY

Conditional Aggregation entfaltet ihre volle Wirkung erst im Zusammenspiel mit GROUP BY, weil dadurch bedingte Kennzahlen nicht nur für die gesamte Tabelle, sondern für jede Gruppe einzeln berechnet werden. Ein Report, der pro Kunde die Anzahl bezahlter, offener und stornierter Bestellungen ausweisen soll, kombiniert GROUP BY customer_id mit mehreren COUNT(CASE WHEN...)-Ausdrücken, jeweils mit einer eigenen Statusbedingung. Jede Gruppe erhält dabei ihre eigenen, unabhängig berechneten Werte für jede der bedingten Kennzahlen.

Wichtig ist, dass die Bedingung innerhalb der Aggregatfunktion nicht mit einer WHERE-Klausel auf Zeilenebene verwechselt wird. Eine WHERE-Bedingung würde Zeilen bereits vor der Aggregation komplett aus der Gruppe entfernen und alle anderen Kennzahlen ebenfalls verfälschen. Conditional Aggregation dagegen behält alle Zeilen der Gruppe für die Gesamtzählung, filtert aber gezielt innerhalb jeder einzelnen Aggregatfunktion, was der entscheidende konzeptionelle Unterschied zwischen einer WHERE-Bedingung und Conditional Aggregation via CASE WHEN oder FILTER ist.


-- Conditional aggregation per customer group, WHERE would remove other rows entirely
SELECT
    customer_id,
    COUNT(CASE WHEN status = 'paid'      THEN 1 END) AS paid_orders,
    COUNT(CASE WHEN status = 'open'      THEN 1 END) AS open_orders,
    COUNT(CASE WHEN status = 'cancelled' THEN 1 END) AS cancelled_orders,
    COUNT(*)                                          AS total_orders
FROM orders
GROUP BY customer_id
ORDER BY total_orders DESC;

7. Prozentanteile und Quoten aus bedingten Zählungen berechnen

Ein besonders praktischer Anwendungsfall für Conditional Aggregation ist die direkte Berechnung von Prozentanteilen innerhalb derselben Abfrage, ohne dass Rohzahlen erst ins Reporting-Tool exportiert und dort weiterverarbeitet werden müssen. Die Formel lautet typischerweise 100.0 mal die bedingte Zählung geteilt durch die Gesamtzählung, wobei NULLIF die Gesamtzählung vor einer Division durch null schützt. Diese Kombination aus Conditional Aggregation und Division ist die Grundlage nahezu jeder Konversions- oder Fehlerquote in einem SQL-Report.

Bei Datenbanksystemen, die Ganzzahldivision durchführen, wie es in älteren MySQL-Konfigurationen vorkommen kann, muss mindestens ein Operand der Division explizit als Dezimalzahl behandelt werden, meist durch die 100.0 statt 100 als Multiplikator. Ohne diesen expliziten Dezimalpunkt liefert die Division bei Conditional Aggregation in solchen Fällen gerundete Ganzzahlen wie 0 oder 1 statt eines aussagekräftigen Prozentwerts, was in der Praxis zu falsch interpretierten Dashboards führt.

8. Performance: ein Scan statt mehrerer Unterabfragen

Der Performance-Vorteil von Conditional Aggregation gegenüber mehreren separaten Abfragen mit anschließendem JOIN liegt darin, dass die Datenbank die relevante Tabelle oder den relevanten Index nur einmal lesen muss, statt einmal pro Kennzahl. Bei einer Faktentabelle mit mehreren Millionen Zeilen kann der Unterschied zwischen einem einzigen Table-Scan und zehn separaten Scans mit anschließendem JOIN mehrere Sekunden Laufzeitunterschied bedeuten, besonders wenn kein passender Index existiert und jede Abfrage einen Full Table Scan auslöst.

Ein weiterer Performance-Aspekt betrifft den Query-Planer: Bei Conditional Aggregation sieht der Planer eine einzige Abfrage mit einer klaren GROUP-BY-Struktur und kann diese in der Regel effizient mit einem Hash- oder Sort-basierten Aggregations-Plan ausführen. Bei mehreren separaten Abfragen mit nachträglichem JOIN muss der Planer zusätzlich die Join-Strategie zwischen den Zwischenergebnissen optimieren, was zusätzlichen Planungsaufwand und potenziell zusätzliche Sortierschritte bedeutet, die bei Conditional Aggregation von vornherein entfallen.

9. CASE WHEN, FILTER und separate Subqueries im Vergleich

Die folgende Übersicht vergleicht die drei gängigen Ansätze, um mehrere bedingte Kennzahlen aus derselben Tabelle zu berechnen, und zeigt, wann welcher Ansatz für Conditional Aggregation sinnvoll ist.

Ansatz Table Scans Datenbank-Support Lesbarkeit
CASE WHEN in Aggregatfunktion 1 Alle SQL-Datenbanken Gut, aber verschachtelt bei vielen Bedingungen
FILTER-Klausel 1 PostgreSQL, nicht MySQL/SQL Server Sehr klar, Bedingung direkt sichtbar
Separate Subqueries + JOIN N (eine pro Kennzahl) Alle SQL-Datenbanken Aufwendig bei vielen Kennzahlen
Anwendungscode nachträglich N, plus Transfer aller Rohdaten Unabhängig von der Datenbank Logik verteilt über zwei Schichten

In der Praxis ist CASE WHEN die portabelste Variante von Conditional Aggregation, während die FILTER-Klausel dort, wo sie verfügbar ist, die klarere und oft auch geringfügig performantere Wahl ist, weil der Query-Planer die Filterbedingung direkt erkennt, statt sie aus einem CASE-Ausdruck ableiten zu müssen. Separate Subqueries oder eine Verarbeitung im Anwendungscode sollten für mehrere Kennzahlen aus derselben Tabelle die letzte Wahl sein.

Mironsoft

SQL-Reporting, KPI-Dashboards und Query-Optimierung

Zehn Kennzahlen, zehn Abfragen? Das geht auch in einer.

Wir bauen Reporting-Abfragen mit Conditional Aggregation, die mehrere Kennzahlen in einem einzigen Table-Scan berechnen, statt Dashboards mit dutzenden separaten Abfragen zu überladen.

Query-Refactoring

Mehrere Abfragen zu einer einzigen Conditional-Aggregation-Abfrage zusammenführen

Dashboard-Performance

Reduzierung der Table-Scans für schnellere, konsistentere Dashboards

Datenbank-Beratung

Auswahl zwischen CASE WHEN und FILTER passend zu eurer Datenbankplattform

Wer Conditional Aggregation konsequent einsetzt, ersetzt eine wachsende Zahl separater Abfragen durch wenige, gut strukturierte Reporting-Queries, die sich einfacher warten, testen und dokumentieren lassen als ein Geflecht aus Subqueries und nachgelagerter Anwendungslogik.

10. Zusammenfassung

Conditional Aggregation kombiniert Bedingungen mit Aggregatfunktionen, um mehrere Kennzahlen in einem einzigen Durchlauf über die Tabelle zu berechnen. Das klassische Muster nutzt CASE WHEN innerhalb von COUNT oder SUM, wobei bei SUM ein explizites ELSE 0 nötig ist, um NULL statt 0 zu vermeiden. Die FILTER-Klausel ist die modernere, klarere Alternative, allerdings nicht in allen Datenbanksystemen verfügbar.

Der größte Nutzen von Conditional Aggregation liegt in der Reduktion der Table Scans: Statt einer Abfrage pro Kennzahl entsteht eine einzige Abfrage mit beliebig vielen bedingten Spalten. NULLIF schützt dabei zuverlässig vor Division durch null bei Prozentberechnungen, und die richtige Kombination mit GROUP BY liefert bedingte Kennzahlen pro Gruppe statt nur für die Gesamttabelle.

Conditional Aggregation: das Wichtigste auf einen Blick

CASE WHEN Grundmuster

COUNT(CASE WHEN bedingung THEN 1 END) für Zählungen, SUM(CASE WHEN bedingung THEN betrag ELSE 0 END) für Summen.

FILTER-Klausel

AGGREGATFUNKTION(ausdruck) FILTER (WHERE bedingung), klarer als CASE WHEN, aber nicht überall verfügbar.

NULL beachten

Ohne ELSE 0 liefert SUM bei fehlenden Treffern NULL, nicht 0. COALESCE schafft Abhilfe.

Performance

Ein Table-Scan für beliebig viele Kennzahlen, statt einer Abfrage pro Kennzahl.

11. FAQ: Conditional Aggregation

1Was ist Conditional Aggregation?
Eine Bedingung wird direkt mit einer Aggregatfunktion kombiniert, meist über CASE WHEN oder FILTER, um mehrere Kennzahlen in einem Durchlauf zu berechnen.
2Warum ELSE 0 bei SUM?
Ohne ELSE 0 liefert SUM NULL statt 0, wenn keine Zeile passt. COUNT braucht das nicht, weil es NULL ignoriert.
3FILTER vs. CASE WHEN?
FILTER ist klarer, aber nicht überall verfügbar. CASE WHEN ist portabler und funktioniert in jeder SQL-Datenbank.
4Kann MySQL FILTER nutzen?
Nein, MySQL unterstützt FILTER nicht. Dort ist CASE WHEN die einzige Option für Conditional Aggregation.
5Prozentquote berechnen?
100.0 mal bedingte Zählung geteilt durch NULLIF(Gesamtzählung, 0), das verhindert Division durch null.
6Schneller als separate Abfragen?
Ja, meist deutlich, weil die Tabelle nur einmal statt mehrfach gelesen wird.
7Kombination mit GROUP BY?
Ja, der Regelfall. Jede Gruppe erhält ihre eigenen bedingten Kennzahlen.
8NULL in der geprüften Spalte?
Der Vergleich ergibt unbekannt, die Zeile wird NULL und von COUNT ignoriert, nicht fälschlich gezählt.
9Verwechslung mit WHERE?
WHERE entfernt Zeilen für die ganze Abfrage, Conditional Aggregation filtert nur innerhalb einzelner Aggregatfunktionen.
10Lohnt sich das schon bei zwei Kennzahlen?
Ja, auch bei zwei Kennzahlen spart man einen Scan und einen JOIN, der Effekt wächst mit jeder weiteren Kennzahl.