Najczęstsze pytanie na rozmowie SQL:
ROW_NUMBER vs RANK vs DENSE_RANK – czym się różnią i kiedy ich używać?
Jeśli byłeś na rozmowie rekrutacyjnej na stanowisko analityka, data engineera czy BI developera, bardzo możliwe, że padło to pytanie:
„Explain ROW_NUMBER vs RANK vs DENSE_RANK.”
To tzw. „Big Three” ranking functions w SQL.
I choć różnice wydają się subtelne, wybór złej funkcji może całkowicie zmienić logikę biznesową raportu.

ROW_NUMBER()
Każdy wiersz dostaje unikalny numer.
Brak remisów. Brak luk.
Przykład wyników:
1, 2, 3, 4
Jeśli dwie osoby mają taki sam wynik – i tak dostaną różne numery.
RANK()
W przypadku remisu wiersze dostają tę samą pozycję.
Kolejna pozycja zostaje „przeskoczona”.
Przykład:
1, 2, 2, 4
(„3” znika, bo były dwa drugie miejsca)
DENSE_RANK()
Remisy również mają tę samą pozycję.
Ale numeracja nie ma luk.
Przykład:
1, 2, 2, 3
Zobaczmy to na przykładzie
Załóżmy, że mamy ranking wyników:
| Score | ? |
|---|---|
| 95 | |
| 90 | |
| 90 | |
| 85 |
W zależności od funkcji otrzymamy:
- ROW_NUMBER: 1, 2, 3, 4
- RANK: 1, 2, 2, 4
- DENSE_RANK: 1, 2, 2, 3
Różnica wygląda niewinnie.
W praktyce może zmienić premię sprzedażową, dashboard KPI albo raport dla zarządu.
Wrong function = wrong business logic
To nie jest tylko pytanie rekrutacyjne.
Zła funkcja rankingowa może:
- zdublować rekordy przy deduplikacji,
- błędnie policzyć „Top 3”,
- zmienić ranking najlepszych sprzedawców,
- zaburzyć dashboard z leaderboardem.
W komentarzach do oryginalnego posta wiele osób zwracało uwagę, że użycie RANK() zamiast ROW_NUMBER() w deduplikacji potrafi zostawić dwa „najnowsze” rekordy.
Mała różnica w SQL. Duża różnica w biznesie.
ROW_NUMBER – gdy liczy się unikalna kolejność
Najczęstsze przypadki:
- Paginacja (strona 1, 2, 3…)
- Systemy kolejkowe (pozycja zgłoszenia)
- Deduplikacja (zostaw najnowszy rekord)
Przykład deduplikacji:
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY updated_at DESC) AS rn
FROM users
) t
WHERE rn = 1;
Tu ROW_NUMBER() jest właściwym wyborem.RANK() mógłby zostawić więcej niż jeden rekord.
RANK – gdy liczy się rzeczywista pozycja
Idealne do:
- Rankingów sprzedaży
- Wyników sportowych
- Wyszukiwarek (ranking trafności)
Jeśli dwóch sprzedawców ma ten sam wynik – obaj są na 2. miejscu.
A kolejne miejsce to 4.
To często najbardziej „uczciwa” logika rankingowa.
DENSE_RANK – gdy nie chcesz luk
Sprawdza się w:
- Kategoriach ocen (A, B, C)
- Przydzielaniu nagród
- „Top 5 produktów”
Tu nie chcemy, by po dwóch drugich miejscach pojawiło się czwarte.
Jak wybrać właściwą funkcję?
Zadaj sobie pytanie:
- Czy każdy wiersz musi mieć unikalny numer? → ROW_NUMBER
- Czy remis powinien powodować „dziurę” w numeracji? → RANK
- Czy remis bez luk jest bardziej logiczny? → DENSE_RANK
To nie kwestia składni.
To kwestia logiki biznesowej.
Dlaczego to najczęstsze pytanie rekrutacyjne?
Bo pokazuje, czy:
- rozumiesz różnicę między danymi a ich interpretacją,
- myślisz o konsekwencjach biznesowych,
- potrafisz dobrać funkcję do celu,
- rozumiesz window functions.
Rekruter nie sprawdza tylko SQL-a.
Sprawdza sposób myślenia.
Podsumowanie
| Funkcja | Remisy | Luki w numeracji | Główne zastosowanie |
|---|---|---|---|
| ROW_NUMBER | ❌ | ❌ | Deduplikacja, paginacja |
| RANK | ✅ | ✅ | Rankingi, leaderboard |
| DENSE_RANK | ✅ | ❌ | Kategorie, top N |
Jedna linijka SQL może zmienić cały raport.
Dlatego warto rozumieć różnice — nie tylko na rozmowie kwalifikacyjnej, ale w realnych projektach.