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
Laufende Summe in SQL – SUM() OVER statt Schleife in der Anwendung
Kontostand nach jeder Buchung, kumulierter Umsatz im Jahr, Restbestand nach jeder Entnahme: Alles dieselbe Frage. Mit einer Fensterfunktion beantwortet die Datenbank sie in einer Abfrage – inklusive gleitendem Durchschnitt.
NULL in SQL – warum COUNT(spalte) lügt und wo die leeren Werte landen
NULL ist kein Wert, sondern die Abwesenheit eines Werts. Deshalb zählt COUNT(spalte) anders als COUNT(*), summiert SUM() an leeren Zeilen vorbei und landen beim Sortieren alle Lücken am selben Ende.
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.