Ranglisten in SQL mit Fensterfunktionen – ROW_NUMBER, RANK und PARTITION BY
Für eine Rangliste brauchst du keine Zählerei im Code. ROW_NUMBER() und RANK() vergeben den Platz direkt in SQL – auch getrennt nach Gruppen. Ich zeige dir den Unterschied und wann du was nimmst.
Für die Rangliste in meinem Browsergame wollte ich zu jedem Spieler den Platz ausgeben. Der Anfänger-Reflex: alle Zeilen holen und im Code hochzählen. Viel sauberer geht das direkt in SQL mit Fensterfunktionen – die rechnen über eine „Gruppe" von Zeilen, ohne sie zu einer einzigen zusammenzufassen.
Platz vergeben mit ROW_NUMBER()
SELECT
ROW_NUMBER() OVER (ORDER BY score DESC) AS platz,
name,
score
FROM players
ORDER BY score DESC;OVER (ORDER BY score DESC) ist das „Fenster": Sortiere gedanklich nach Punkten und nummeriere durch. Ergebnis: 1, 2, 3, 4 … – jeder Platz genau einmal.
Gleichstände: RANK() vs. DENSE_RANK()
Was, wenn zwei Spieler exakt gleich viele Punkte haben? ROW_NUMBER() vergibt trotzdem 1 und 2 (willkürlich). Meist willst du aber, dass beide denselben Platz bekommen:
SELECT
RANK() OVER (ORDER BY score DESC) AS platz, -- 1, 2, 2, 4 (überspringt die 3)
DENSE_RANK() OVER (ORDER BY score DESC) AS platz_dicht, -- 1, 2, 2, 3 (ohne Lücke)
name, score
FROM players;RANK(): gleicher Score = gleicher Platz, danach wird der ausgelassene Platz übersprungen (klassische Sport-Rangliste).DENSE_RANK(): gleich, aber ohne Lücke im Zähler.
Rang pro Gruppe mit PARTITION BY
Richtig stark wird es, wenn du je Gruppe ranken willst – etwa den besten Spieler pro Land:
SELECT
land,
name,
score,
RANK() OVER (PARTITION BY land ORDER BY score DESC) AS platz_im_land
FROM players;PARTITION BY land startet die Zählung für jedes Land neu. So bekommst du eine Rangliste pro Land in einer einzigen Abfrage.
Das Beste: Fensterfunktionen laufen in PostgreSQL, MySQL 8+, SQLite 3.25+ und SQL Server gleich. Und weil die Datenbank das Ranking übernimmt, bleibt dein Anwendungscode schlank.
Wenn du ein Projekt mit Rangliste, Statistiken oder Auswertungen planst, baue ich dir die passende Datenbank dahinter – meld dich über bymw.de.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
Wie viel mehr als gestern? Differenz zur Vorzeile mit LAG() in SQL
„Wie viele Besucher heute im Vergleich zu gestern?" – der Reflex ist ein Self-Join auf die Vorzeile. Mit der Fensterfunktion LAG() bekommst du den Wert der vorherigen Zeile direkt daneben, ohne die Tabelle ein zweites Mal anzufassen.
Vergleich zur Vorzeile mit LAG() – wie stark hat sich ein Wert verändert
„Wie viele Besucher mehr als gestern?" ist in SQL erstaunlich fummelig, wenn man es mit einem Self-Join löst. Mit der Fensterfunktion LAG() greifst du direkt auf die vorherige Zeile zu – und rechnest die Differenz in einer einzigen, lesbaren Abfrage.
WITH RECURSIVE – Kategoriebäume und Kommentar-Threads in einer einzigen Abfrage
Kategorien mit Unterkategorien, Kommentare mit Antworten, Ordner in Ordnern: Die meisten holen sich so etwas mit einer Schleife und einer Abfrage pro Ebene. Eine rekursive CTE holt den ganzen Baum in einem Rutsch – inklusive Tiefe und Pfad.