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
Upsert in SQLite mit ON CONFLICT DO UPDATE
Einfügen oder aktualisieren in einem einzigen Statement – mit ON CONFLICT ... DO UPDATE. Kein vorheriges SELECT, kein Race Condition zwischen Prüfen und Schreiben.
Dateien sicher zum Download ausliefern in PHP – mit readfile() und den richtigen Headern
Ein Download-Link auf eine private Datei ist schnell gefährlich – Pfad-Tricks führen sonst zu fremden Dateien. So lieferst du Downloads sauber aus: geschützt vor „../", speicherschonend und mit korrektem Dateinamen.
Der Eltern-Selektor ist da – bedingtes Styling mit CSS :has()
Jahrelang gab es in CSS keinen Weg, ein Element abhängig von seinem Inhalt zu stylen. Mit :has() geht das endlich – ganz ohne JavaScript. Drei Beispiele, die ich ständig brauche.