Die obersten N Zeilen je Gruppe mit ROW_NUMBER
Das typische Muster aus Partitionierung und Rangfolge für „Top 3 je Kategorie“
Die obersten N Zeilen je Gruppe mit ROW_NUMBER ist eine kostenlose SQL Interview Prep-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des SQL Interview Prep-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der SQL Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Die Frage nach Top-N pro Gruppe
Eine der häufigsten SQL-Fragen im Vorstellungsgespräch klingt einfach: „Geben Sie die 3 bestbezahlten Mitarbeiter in jeder Abteilung zurück.“ Kandidaten, die sofort zu LIMIT greifen, scheitern, weil LIMIT die gesamte Ergebnismenge begrenzt und nicht jede Gruppe einzeln.
Der Interviewer prüft, ob Sie Fensterfunktionen beherrschen. Die Standardlösung lautet: Nummerieren Sie die Zeilen innerhalb jeder Gruppe und behalten Sie anschließend die Zeilen, deren Nummer ≤ N ist. Diese Lektion entwickelt dieses Muster Schritt für Schritt.
Warum LIMIT das Problem nicht lösen kann
Angenommen, Sie schreiben die folgende Abfrage. Sie gibt über die gesamte Tabelle hinweg nur insgesamt 3 Zeilen zurück, nicht 3 pro Abteilung.
LIMIT (oder TOP oder FETCH FIRST) arbeitet mit der endgültigen Ergebnismenge. In Standard-SQL gibt es kein LIMIT pro Gruppe. Wenn ein Interviewer hört, dass Sie für ein Problem pro Gruppe LIMIT 3 vorschlagen, deutet das darauf hin, dass Sie das Prinzip der Partitionierung noch nicht verinnerlicht haben.
-- WRONG: only 3 rows total, not 3 per department
SELECT department, name, salary
FROM employees
ORDER BY salary DESC
LIMIT 3;ROW_NUMBER kennenlernen
ROW_NUMBER() ist eine Fensterfunktion, die jeder Zeile entsprechend einer Sortierung eine eindeutige, lückenlose Ganzzahl zuweist. Ohne weitere Angaben nummeriert sie das gesamte Ergebnis.
Der entscheidende Bestandteil ist PARTITION BY: Die Nummerierung beginnt für jede Gruppe wieder bei 1. Kombinieren Sie PARTITION BY department mit ORDER BY salary DESC, erhält jede Abteilung eine eigene Rangfolge 1, 2, 3, ... nach Gehalt.
SELECT
name,
department,
salary,
ROW_NUMBER() OVER (
PARTITION BY department
ORDER BY salary DESC
) AS rn
FROM employees;Die nummerierte Ausgabe lesen
Nach dem Ausführen der vorherigen Abfrage enthält jede Zeile einen Wert rn. Innerhalb jeder Abteilung erhält das höchste Gehalt den Wert rn = 1, das nächsthöhere den Wert 2 und so weiter. Bei einer neuen Abteilung beginnt die Nummerierung wieder bei 1.
- Vertrieb: Ana (1), Bo (2), Cal (3), Dee (4)
- Entwicklung: Eve (1), Fin (2), Gus (3)
„Top 3 pro Abteilung“ bedeutet nun einfach: „Behalten Sie die Zeilen, für die rn <= 3 gilt.“
rn kann nicht in WHERE gefiltert werden
Der naheliegende nächste Schritt wäre WHERE rn <= 3, aber das funktioniert nicht. Fensterfunktionen werden in der logischen Ausführungsreihenfolge nach der WHERE-Klausel berechnet. Daher existiert das Alias rn noch nicht, wenn WHERE ausgeführt wird.
Diese Falle kommt in Vorstellungsgesprächen häufig vor. Die Lösung besteht darin, die Fensterfunktion in einer Unterabfrage oder CTE zu berechnen und anschließend das Ergebnis dieser inneren Abfrage in einer äußeren Abfrage zu filtern.
-- ERROR: rn does not exist in WHERE
SELECT name, department, salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn
FROM employees
WHERE rn <= 3;Die Standardlösung mit einer CTE
Verpacken Sie die Nummerierung in eine CTE namens ranked und wählen Sie anschließend daraus aus, wobei der Filter im äußeren WHERE steht. Das ist die Lösung, die Interviewer sehen möchten, und sie ist übersichtlich.
Merken Sie sich dieses Grundmuster: Nach der Gruppe partitionieren, nach der Kennzahl sortieren und rn ≤ N in der äußeren Abfrage filtern. Es lässt sich auf Top-1, Top-5 oder jedes beliebige N verallgemeinern, indem Sie nur eine Zahl ändern.
WITH ranked AS (
SELECT
name, department, salary,
ROW_NUMBER() OVER (
PARTITION BY department
ORDER BY salary DESC
) AS rn
FROM employees
)
SELECT name, department, salary
FROM ranked
WHERE rn <= 3
ORDER BY department, rn;Die Variante mit einer Unterabfrage
Wenn der SQL-Dialekt des Interviewers älter ist oder Unterabfragen bevorzugt werden, lässt sich dieselbe Logik in einer abgeleiteten Tabelle innerhalb von FROM unterbringen. Denken Sie daran, dass eine abgeleitete Tabelle ein Alias haben muss (hier r), sonst erhalten Sie einen Syntaxfehler.
CTE und abgeleitete Tabelle sind für dieses Problem austauschbar. Wählen Sie die Variante, die der Interviewer besser lesbar findet; beide sind gleichermaßen korrekt.
SELECT name, department, salary
FROM (
SELECT name, department, salary,
ROW_NUMBER() OVER (
PARTITION BY department ORDER BY salary DESC
) AS rn
FROM employees
) AS r
WHERE rn <= 3;Top-1: Das Beste pro Gruppe
„Finden Sie den bestbezahlten Mitarbeiter in jeder Abteilung“ bedeutet einfach N = 1. Setzen Sie den Filter auf rn = 1.
Warum nicht MAX(salary) mit GROUP BY department? Weil MAX zwar den Gehaltswert liefert, aber nicht die übrigen Spalten der betreffenden Mitarbeiterzeile (Name, Einstellungsdatum usw.). ROW_NUMBER erhält die gesamte Gewinnerzeile, was die Frage normalerweise tatsächlich verlangt.
WITH ranked AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY department ORDER BY salary DESC
) AS rn
FROM employees
)
SELECT name, department, salary, hire_date
FROM ranked
WHERE rn = 1;Einen deterministischen Tiebreaker hinzufügen
ROW_NUMBER gibt immer genau N Zeilen zurück, auch wenn Gehälter gleich sind. Welche der gleich vergüteten Zeilen rn = 1 erhält, ist jedoch zufällig, sofern Sie den Gleichstand nicht auflösen. Wenn zwei Personen 90000 verdienen und Sie nur rn = 1 behalten, ist die Auswahl zwischen verschiedenen Ausführungen nicht vorhersehbar.
Fügen Sie einen sekundären, eindeutigen Sortierschlüssel wie employee_id hinzu, damit das Ergebnis stabil und reproduzierbar ist. Interviewer schätzen Kandidaten, die von sich aus Determinismus ansprechen.
ROW_NUMBER() OVER (
PARTITION BY department
ORDER BY salary DESC, employee_id ASC
) AS rnEin konkretes durchgerechnetes Beispiel
Eine Tabelle sales enthält region, product und revenue. Geben Sie die 2 umsatzstärksten Produkte pro Region zurück. Das Vorgehen ist dasselbe: nach region partitionieren, nach revenue DESC sortieren und rn <= 2 behalten.
Beachten Sie, dass sich nur die Partitionsspalte und die Kennzahlenspalte ändern. Die Struktur ist unabhängig von der jeweiligen Fachdomäne identisch.
WITH ranked AS (
SELECT region, product, revenue,
ROW_NUMBER() OVER (
PARTITION BY region ORDER BY revenue DESC, product
) AS rn
FROM sales
)
SELECT region, product, revenue
FROM ranked
WHERE rn <= 2
ORDER BY region, rn;Performance und wichtige Gesprächspunkte
Wenn Sie über die reine Korrektheit hinaus überzeugen möchten, erwähnen Sie:
- Ein Index auf
(department, salary DESC)hilft der Engine, sortierte Zeilen pro Partition effizient zu erzeugen. - Der Fensteransatz durchläuft die Tabelle einmal und ist damit deutlich besser als eine korrelierte Unterabfrage, die pro Zeile ausgeführt wird.
- Für sehr große Top-N-Abfragen mit N = 1 unterstützen einige Engines
DISTINCT ON(Postgres) als Abkürzung, aberROW_NUMBERist der portable Standard.
Nennen Sie immer Ihren Tiebreaker und bestätigen Sie das geforderte N.
Kurztest
Testen Sie, wie gut Sie das Muster für Top-N pro Gruppe beherrschen.
Zusammenfassung: Top-N pro Gruppe
Das Muster in einem Satz: Nach der Gruppe partitionieren, nach der Kennzahl sortieren, ROW_NUMBER zuweisen und anschließend rn ≤ N in einer äußeren Abfrage behalten.
LIMITbegrenzt die gesamte Ergebnismenge, niemals einzelne Gruppen.- Sie können das Fenster-Alias nicht in
WHEREfiltern; verpacken Sie es in eine CTE oder Unterabfrage. - Fügen Sie für deterministische Ergebnisse einen eindeutigen Tiebreaker hinzu.
- Top-1 behält im Gegensatz zu
MAX+GROUP BYdie gesamte Gewinnerzeile.
Ändern Sie eine Zahl, und dieselbe Abfrage löst Top-1, Top-5 oder jedes beliebige N.
Häufig gestellte Fragen
Ist die Lektion „Die obersten N Zeilen je Gruppe mit ROW_NUMBER“ kostenlos?
Ja — der vollständige Text von „Die obersten N Zeilen je Gruppe mit ROW_NUMBER“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des SQL Interview Prep-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der SQL Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Die obersten N Zeilen je Gruppe mit ROW_NUMBER“?
Das typische Muster aus Partitionierung und Rangfolge für „Top 3 je Kategorie“ Du übst SQL Interview Prep mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um SQL Interview Prep zu starten?
Keine Vorkenntnisse erforderlich. SQL Interview Prep auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.
Wie lange dauert die Lektion „Die obersten N Zeilen je Gruppe mit ROW_NUMBER“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser SQL Interview Prep-Lektion Code schreiben und ausführen?
Ja. Jede SQL Interview Prep-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Die obersten N Zeilen je Gruppe mit ROW_NUMBER
- Gleichstände bei den obersten N Werten behandeln
- Zeilen sicher deduplizieren
- Die aktuellste Zeile je Schlüssel beibehalten