PARTITION BY – Daten gruppieren auf hohem Niveau

In der Welt der SQL-Analyse sind Fensterfunktionen (Window Functions) ein mächtiges Werkzeug, um Daten auf einer neuen Ebene zu betrachten. Besonders die PARTITION BY-Klausel ermöglicht es, Datensätze innerhalb bestimmter Gruppen zu analysieren, ohne dabei einzelne Zeilen zu verlieren – ein entscheidender Unterschied zu klassischen Aggregationen mit GROUP BY.

Dieser Artikel zeigt dir, wie PARTITION BY funktioniert, welche Vorteile es gegenüber traditionellen Gruppierungen bietet und wie du es gezielt einsetzen kannst, um komplexe Auswertungen wie Rangfolgen, gleitende Durchschnitte oder Vorjahresvergleiche direkt in deinen SQL-Abfragen zu berechnen. Schritt für Schritt lernst du, wie Partitionierung in SQL deine Analysen effizienter und präziser macht – selbst bei großen Datenmengen.

Partition by

Was ist PARTITION BY?

Mit PARTITION BY kannst du in SQL Daten in Gruppen aufteilen, ohne dass Zeilen verloren gehen. Stell dir vor, du hast eine Liste von Mitarbeitern und möchtest herausfinden, wer in jeder Abteilung das höchste Gehalt hat. PARTITION BY teilt die Daten nach Abteilungen auf, und dann kannst du Berechnungen innerhalb jeder Gruppe durchführen.

Einfaches Beispiel


SELECT
    MitarbeiterID,
    Abteilung,
    Gehalt,
    RANK() OVER (PARTITION BY Abteilung ORDER BY Gehalt DESC) AS Rang
FROM
    Mitarbeiter;
  

In diesem Beispiel wird jeder Mitarbeiter innerhalb seiner Abteilung nach Gehalt sortiert. Die höchste Person bekommt Rang 1, die nächste Rang 2 usw. So siehst du die Rangfolge pro Abteilung, ohne dass andere Daten verloren gehen.

Unterschied zu GROUP BY

  • GROUP BY fasst Zeilen zusammen und reduziert die Anzahl der Ergebnisse.
  • PARTITION BY behält alle Zeilen und rechnet innerhalb der Gruppen.
  • Praktisch, wenn du Details behalten und trotzdem gruppenweise Berechnungen machen willst.

PARTITION BY im Detail

Mit PARTITION BY kannst du Daten in Gruppen aufteilen und innerhalb dieser Gruppen Berechnungen durchführen – ohne dass Zeilen verloren gehen. Das ist besonders nützlich, wenn du z. B. Mitarbeiter nach Abteilungen sortieren, Rangfolgen erstellen oder Werte vergleichen möchtest.

Wie Partitionen gebildet werden

Eine Partition ist einfach eine Gruppe von Zeilen, die denselben Wert in einer bestimmten Spalte haben. Zum Beispiel kannst du alle Mitarbeiter mit derselben Abteilung in eine Partition stecken. Jede Partition wird dann unabhängig analysiert.


-- Mitarbeiter nach Abteilung in Partitionen einteilen
SELECT
    MitarbeiterID,
    Abteilung,
    Gehalt,
    RANK() OVER (PARTITION BY Abteilung ORDER BY Gehalt DESC) AS Rang
FROM
    Mitarbeiter;
  

In diesem Beispiel wird jeder Mitarbeiter innerhalb seiner Abteilung nach Gehalt sortiert. Die höchste Person bekommt Rang 1, die nächste Rang 2 usw. So siehst du die Rangfolge pro Abteilung, ohne dass andere Daten verloren gehen.

Reihenfolge innerhalb der Partition mit ORDER BY

Die Klausel ORDER BY innerhalb von OVER() bestimmt, wie die Zeilen innerhalb einer Partition sortiert werden. Du kannst damit z. B. die besten Gehälter zuerst anzeigen oder eine zeitliche Reihenfolge herstellen.


-- Mitarbeiter nach Gehalt sortieren innerhalb der Abteilung
SELECT
    MitarbeiterID,
    Abteilung,
    Gehalt,
    ROW_NUMBER() OVER (PARTITION BY Abteilung ORDER BY Gehalt DESC) AS Reihenfolge
FROM
    Mitarbeiter;
  

Mit ROW_NUMBER() bekommt jede Zeile eine eindeutige Nummer innerhalb der Partition. Das ist praktisch, wenn du z. B. den Top-Performer jeder Abteilung identifizieren möchtest.

Vergleich mit vorherigen oder nachfolgenden Werten

Mit den Funktionen LAG() und LEAD() kannst du innerhalb einer Partition auf Werte der vorherigen oder nächsten Zeile zugreifen. So lassen sich Unterschiede zwischen aufeinanderfolgenden Werten berechnen, z. B. Gehaltssteigerungen oder Umsatzveränderungen.


-- Vorheriges und nächstes Gehalt pro Abteilung
SELECT
    MitarbeiterID,
    Abteilung,
    Gehalt,
    LAG(Gehalt) OVER (PARTITION BY Abteilung ORDER BY Gehalt) AS VorherigesGehalt,
    LEAD(Gehalt) OVER (PARTITION BY Abteilung ORDER BY Gehalt) AS NaechstesGehalt
FROM
    Mitarbeiter;
  

LAG(Gehalt) zeigt das Gehalt des vorherigen Mitarbeiters innerhalb derselben Abteilung, LEAD(Gehalt) das Gehalt des nächsten Mitarbeiters. So kannst du z. B. berechnen, um wie viel das Gehalt im Vergleich zur vorherigen Person steigt.

Zusammenfassung

  • PARTITION BY teilt Daten in Gruppen (Partitionen) auf.
  • ORDER BY legt die Reihenfolge der Zeilen innerhalb der Partition fest.
  • RANK(), DENSE_RANK() oder ROW_NUMBER() erzeugen Rangfolgen innerhalb jeder Partition.
  • LAG() und LEAD() ermöglichen den Vergleich von Werten innerhalb der Partition.
  • Alle Zeilen bleiben erhalten – du siehst sowohl die Originaldaten als auch die berechneten Werte.

Durch diese Kombination kannst du komplexe Analysen auf Gruppenebene durchführen, ohne dass du Daten zusammenfassen oder verlieren musst. Es ist ein mächtiges Werkzeug, um tiefergehende Einblicke in deine Daten zu bekommen.

Praktische Anwendungsbeispiele

Um das Verständnis für PARTITION BY zu vertiefen, schauen wir uns einige typische Szenarien aus der Praxis an. Diese Beispiele zeigen, wie du Rangfolgen erstellen, laufende Summen berechnen oder Vorjahresvergleiche durchführen kannst – alles innerhalb von Gruppen, ohne Zeilen zu verlieren.

1. Rangfolgen pro Gruppe mit RANK() und DENSE_RANK()

Mit RANK() und DENSE_RANK() kannst du die Position von Werten innerhalb einer Gruppe bestimmen, z. B. die besten Mitarbeiter pro Abteilung.

SELECT
    MitarbeiterID,
    Abteilung,
    Gehalt,
    RANK() OVER (PARTITION BY Abteilung ORDER BY Gehalt DESC) AS Rang,
    DENSE_RANK() OVER (PARTITION BY Abteilung ORDER BY Gehalt DESC) AS DichtRang
FROM
    Mitarbeiter;
  
Unterschied: RANK() überspringt Nummern bei Gleichständen, DENSE_RANK() nicht. So siehst du z. B. mehrere Top-Performer auf Rang 1 ohne Lücken in der Rangfolge.

2. Laufende Summen oder gleitende Durchschnitte innerhalb einer Partition

Du kannst mit SUM() oder AVG() innerhalb von Partitionen laufende Summen oder Durchschnitte berechnen. Praktisch, z. B. für Umsatz- oder Punktestand-Analysen.

SELECT
    Monat,
    Region,
    Umsatz,
    SUM(Umsatz) OVER (PARTITION BY Region ORDER BY Monat) AS LaufendeSumme,
    AVG(Umsatz) OVER (PARTITION BY Region ORDER BY Monat ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS GleitenderDurchschnitt
FROM
    Verkaufszahlen;
  
Hier wird die Summe pro Region Monat für Monat aufaddiert, und der gleitende Durchschnitt berücksichtigt die letzten 3 Monate. So erkennst du Trends innerhalb jeder Gruppe.

3. Vorjahresvergleiche mit LAG()

Mit LAG() kannst du Werte aus vorherigen Zeilen abrufen, z. B. das Umsatzniveau des Vorjahres.

SELECT
    Jahr,
    Kategorie,
    Umsatz,
    LAG(Umsatz) OVER (PARTITION BY Kategorie ORDER BY Jahr) AS UmsatzVorjahr,
    Umsatz - LAG(Umsatz) OVER (PARTITION BY Kategorie ORDER BY Jahr) AS Differenz
FROM
    Verkaufszahlen;
  
So siehst du, wie sich der Umsatz in jeder Kategorie im Vergleich zum Vorjahr verändert hat – und das alles, ohne die Originaldaten zu verlieren.

Zusammenfassung

  • Mit RANK() und DENSE_RANK() erstellst du Ranglisten innerhalb von Gruppen.
  • Laufende Summen oder gleitende Durchschnitte helfen, Trends pro Partition zu erkennen.
  • LAG() und LEAD() ermöglichen Vergleiche mit vorherigen oder nächsten Zeilen.
  • Alle Berechnungen erfolgen innerhalb der Gruppen – Originaldaten bleiben vollständig sichtbar.

PARTITION BY vs. GROUP BY – ein ausführlicher Vergleich

Viele Anfänger sind unsicher, wann sie PARTITION BY und wann sie GROUP BY verwenden sollten. Beide Funktionen teilen Daten nach bestimmten Kriterien, aber sie unterscheiden sich grundlegend in der Art, wie Ergebnisse erzeugt werden.

1. Gemeinsamkeiten

Sowohl GROUP BY als auch PARTITION BY gruppieren Daten nach einer oder mehreren Spalten. Das Ziel ist, bestimmte Muster oder Berechnungen innerhalb dieser Gruppen zu erkennen.

2. Hauptunterschiede

  • GROUP BY fasst die Daten zusammen. Ergebnis: weniger Zeilen. Beispiel: Gesamtsumme pro Abteilung.
    
    SELECT Abteilung, SUM(Gehalt) AS GesamtGehalt
    FROM Mitarbeiter
    GROUP BY Abteilung;
          
    Hier bekommst du nur eine Zeile pro Abteilung – die Details der einzelnen Mitarbeiter gehen verloren.
  • PARTITION BY behält alle Zeilen und berechnet Werte innerhalb jeder Gruppe. Beispiel: Rangfolge pro Abteilung.
    
    SELECT
        MitarbeiterID,
        Abteilung,
        Gehalt,
        RANK() OVER (PARTITION BY Abteilung ORDER BY Gehalt DESC) AS Rang
    FROM Mitarbeiter;
          
    Hier bleibt jeder Mitarbeiter sichtbar, und du siehst die Rangfolge innerhalb der Abteilung.

3. Wann welches nutzen?

  • Verwende GROUP BY, wenn du aggregierte Kennzahlen wie Summen oder Durchschnitte pro Gruppe benötigst und die Detailzeilen nicht brauchst.
  • Verwende PARTITION BY, wenn du sowohl Detaildaten als auch gruppenbezogene Berechnungen sehen möchtest, z. B. Ranglisten, laufende Summen oder Vorjahresvergleiche.

Kurz gesagt: GROUP BY reduziert Zeilen, PARTITION BY behält sie und liefert zusätzliche Berechnungen innerhalb der Gruppen. Beide Methoden ergänzen sich, je nach Analysebedarf.

Erweiterte Techniken mit PARTITION BY

Nachdem wir die Grundlagen von PARTITION BY verstanden haben, schauen wir uns nun fortgeschrittene Techniken an, mit denen du noch flexiblere Analysen durchführen kannst.

1. Mehrere Partitionsebenen

Du kannst Daten nicht nur nach einer Spalte, sondern nach mehreren Spalten partitionieren. Zum Beispiel nach Jahr und Monat oder nach Abteilung und Team. Jede Kombination bildet eine eigene Gruppe.


SELECT
    Jahr,
    Monat,
    Abteilung,
    Umsatz,
    RANK() OVER (PARTITION BY Jahr, Abteilung ORDER BY Umsatz DESC) AS Rang
FROM Verkaufszahlen;
  

Hier wird der Umsatz innerhalb jeder Abteilung pro Jahr gerankt. So bekommst du eine feingranulare Rangfolge, die zwei Ebenen berücksichtigt.

2. Kombination mit ROWS oder RANGE für Frame-spezifische Berechnungen

Mit ROWS oder RANGE kannst du definieren, welche Zeilen für Berechnungen innerhalb der Partition betrachtet werden. Das ist praktisch für gleitende Summen oder Durchschnittswerte.


SELECT
    Monat,
    Region,
    Umsatz,
    SUM(Umsatz) OVER (
        PARTITION BY Region
        ORDER BY Monat
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) AS GleitendeSumme
FROM Verkaufszahlen;
  

Hier wird die Summe über den aktuellen und die zwei vorherigen Monate berechnet – perfekt, um kurzfristige Trends zu erkennen.

3. Einsatz in komplexen Abfragen

PARTITION BY lässt sich auch in Unterabfragen oder in Kombination mit mehreren Fensterfunktionen einsetzen. So kannst du z. B. gleichzeitig Rangfolgen, gleitende Durchschnitte und Vergleichswerte berechnen, ohne die Daten zu aggregieren.


SELECT
    MitarbeiterID,
    Abteilung,
    Gehalt,
    RANK() OVER (PARTITION BY Abteilung ORDER BY Gehalt DESC) AS Rang,
    AVG(Gehalt) OVER (PARTITION BY Abteilung) AS Durchschnittsgehalt
FROM Mitarbeiter;
  

So siehst du für jeden Mitarbeiter sowohl den Rang in der Abteilung als auch den durchschnittlichen Wert der Gruppe – alles in einer einzigen Abfrage.

Kurze Zusammenfassung

  • Mehrere Partitionsebenen ermöglichen detailliertere Analysen.
  • ROWS oder RANGE definieren genau, welche Zeilen in Berechnungen einbezogen werden.
  • Die Kombination mehrerer Fensterfunktionen erlaubt komplexe Analysen in einer einzigen Abfrage.

Mit diesen Techniken wird PARTITION BY zu einem sehr flexiblen Werkzeug, das weit über einfache Ranglisten oder laufende Summen hinausgeht.

Performance und Best Practices

PARTITION BY ist ein sehr mächtiges Werkzeug, kann aber bei großen Tabellen die Performance beeinflussen. Mit ein paar Tipps kannst du sicherstellen, dass deine Abfragen schnell und effizient bleiben.

1. Indexierung der partitionierten Spalten

Wenn du häufig nach bestimmten Spalten partitionierst, kann ein Index die Abfrage deutlich beschleunigen. Ein Index sorgt dafür, dass die Daten schneller gefunden werden, bevor die Berechnungen stattfinden.

-- Beispiel: Index auf Abteilung und Gehalt
CREATE INDEX idx_mitarbeiter_abteilung_gehalt
ON Mitarbeiter (Abteilung, Gehalt);
  

2. Vermeidung zu vieler Partitionen

Jede Partition bedeutet zusätzlichen Rechenaufwand. Wenn du zu viele kleine Partitionen hast, kann das die Abfrage verlangsamen. Überlege also, welche Spalten wirklich sinnvoll sind, um Partitionen zu bilden.

3. Kombination mit ORDER BY und Frame-Funktionen bewusst einsetzen

Funktionen wie ROWS BETWEEN oder RANGE können bei großen Datenmengen sehr rechenintensiv werden. Prüfe, ob du wirklich alle Zeilen in den Frame aufnehmen musst oder ob ein kleineres Fenster ausreicht.

4. Typische Fallstricke vermeiden

  • Partition nach Spalten, die sehr viele unterschiedliche Werte haben → viele kleine Partitionen → langsamer.
  • Unnötige Berechnungen auf großen Tabellen durchführen → besser auf benötigte Teilmengen einschränken.
  • Vergessen, die Reihenfolge (ORDER BY) innerhalb der Partition anzugeben → Ergebnisse können unerwartet sein.

Kurze Zusammenfassung

  • Indexe auf partitionierten Spalten verbessern die Performance.
  • Nur sinnvolle Partitionen bilden, um unnötige Berechnungen zu vermeiden.
  • Frame-Funktionen gezielt einsetzen und nicht zu große Fenster wählen.
  • Abfragen vor dem Einsatz auf großen Tabellen testen.
Mit diesen Best Practices stellst du sicher, dass PARTITION BY-Abfragen effizient bleiben und du trotzdem die Vorteile der detaillierten Analysen nutzen kannst.

Fazit

PARTITION BY ist ein äußerst nützliches Werkzeug in SQL, um Daten innerhalb von Gruppen zu analysieren, ohne Zeilen zu verlieren. Ob Rangfolgen, laufende Summen, gleitende Durchschnitte oder Vorjahresvergleiche – mit Partitionen behältst du die Kontrolle über deine Daten und erhältst gleichzeitig wertvolle Einblicke.

Im Vergleich zu GROUP BY bietet PARTITION BY den Vorteil, dass alle Details sichtbar bleiben und du trotzdem Berechnungen innerhalb der Gruppen durchführen kannst. In Kombination mit ORDER BY, LAG(), LEAD() oder Frame-Funktionen wie ROWS und RANGE lassen sich komplexe Analysen elegant lösen.

Denke bei großen Tabellen an Performance: Indexe auf partitionierten Spalten, sinnvolle Partitionen und bewusster Einsatz von Frames helfen, Abfragen effizient zu halten. So kannst du die Vorteile von PARTITION BY voll ausschöpfen.