RANK a DENSE_RANK przy remisach
Klasyczne pytanie o numerację z lukami i bez luk, gdy wartości są równe
RANK a DENSE_RANK przy remisach to bezpłatna lekcja SQL Interview Prep na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej SQL Interview Prep, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs SQL Interview Prep zawiera 4 lekcji w sumie.
Trzy funkcje rankingowe obok siebie
SQL udostępnia trzy okienkowe funkcje rankingowe, a najczęściej zadawane pytanie dotyczące funkcji okienkowych brzmi: czym różnią się one w przypadku remisów:
- ROW_NUMBER — zawsze unikalny; remisujące wiersze otrzymują arbitralnie różne numery.
- RANK — remisujące wiersze mają tę samą rangę, a następna ranga jest pomijana (powstaje luka).
- DENSE_RANK — remisujące wiersze mają tę samą rangę, a następna ranga nie jest pomijana (nie ma luki).
Umiejętność natychmiastowego wyjaśnienia tej różnicy jest wiarygodnym sygnałem podczas rozmowy kwalifikacyjnej.
Konkretna przykładowa tabela
Wyobraźmy sobie pięć wyników uporządkowanych malejąco: 100, 90, 90, 80, 70. Zobaczmy, jak każda funkcja je ponumeruje.
- ROW_NUMBER: 1, 2, 3, 4, 5
- RANK: 1, 2, 2, 4, 5 (pomija 3 po remisie)
- DENSE_RANK: 1, 2, 2, 3, 4 (bez pominięcia)
Proszę zapamiętać przykład 100/90/90/80/70 — pozwala natychmiast odpowiedzieć na to pytanie.
SELECT
score,
ROW_NUMBER() OVER (ORDER BY score DESC) AS rownum,
RANK() OVER (ORDER BY score DESC) AS rnk,
DENSE_RANK() OVER (ORDER BY score DESC) AS dense
FROM scores;Jak RANK oblicza lukę
RANK przypisuje każdemu wierszowi rangę równą jeden plus liczba wierszy, które ściśle go poprzedzają w ustalonej kolejności. Dwa wiersze z remisem przy wartości 90 są poprzedzone przez jeden wiersz (100), więc oba otrzymują rangę 2. Następna, niższa wartość jest poprzedzona przez trzy wiersze, więc otrzymuje rangę 4.
Dlatego RANK odzwierciedla punktację zawodów: remisowi srebrni medaliści i brak brązowego medalu.
-- scores 100,90,90,80 -> RANK = 1,2,2,4
SELECT score, RANK() OVER (ORDER BY score DESC) AS rnk
FROM scores;Jak DENSE_RANK unika luk
DENSE_RANK przypisuje rangę równą jeden plus liczba różnych wartości poprzedzających bieżącą wartość. Po remisie przy wartości 90 przed wartością 80 występowały tylko dwie różne wartości (100 i 90), więc otrzymuje ona rangę 3 — bez luki.
Używaj DENSE_RANK, gdy liczą się pozycje różnych wartości, na przykład „drugie najwyższe wynagrodzenie”, gdzie remisy powinny być liczone tylko raz.
-- scores 100,90,90,80 -> DENSE_RANK = 1,2,2,3
SELECT score, DENSE_RANK() OVER (ORDER BY score DESC) AS dense
FROM scores;Kiedy wybrać poszczególne funkcje
Krótki przewodnik decyzyjny, który rekruterzy lubią słyszeć:
- Potrzebuje Pan/Pani dokładnie jednego wiersza na każdą pozycję (najnowszy rekord, paginacja)? → ROW_NUMBER.
- Potrzebuje Pan/Pani rankingu, w którym osoby z remisem zajmują tę samą pozycję, a luki są prawidłowe (ranking sportowy, 3 najlepsze wyniki z uwzględnieniem remisów)? → RANK.
- Potrzebuje Pan/Pani N-tej różnej wartości (N-tego najwyższego wynagrodzenia)? → DENSE_RANK.
Niewłaściwy wybór zmienia zwracane wiersze, dlatego należy głośno uzasadnić swoją decyzję.
Ranking w partycjach
Wszystkie trzy funkcje przyjmują PARTITION BY, aby niezależnie tworzyć ranking w każdej grupie. Każda partycja zaczyna ranking od pozycji 1.
W tym przykładzie każdy dział tworzy ranking własnych pracowników według wynagrodzenia, a remisy są obsługiwane przez DENSE_RANK. Najlepiej zarabiająca osoba w każdym dziale zajmuje pozycję 1, a pracownicy o takim samym wynagrodzeniu zajmują tę samą pozycję.
SELECT
department,
name,
salary,
DENSE_RANK() OVER (
PARTITION BY department
ORDER BY salary DESC
) AS salary_rank
FROM employees;Przykład: 3 najlepsze wyniki z uwzględnieniem remisów
„Zwróć 3 najwyższe wynagrodzenia w każdym dziale, a jeśli kilka osób zajmuje ex aequo trzecie miejsce, uwzględnij je wszystkie”. Wymaga to użycia RANK lub DENSE_RANK, a nie ROW_NUMBER.
Użycie DENSE_RANK <= 3 zachowuje trzy najwyższe różne poziomy wynagrodzeń oraz każdego pracownika na tych poziomach — dokładnie to oznacza uwzględnienie remisów.
SELECT department, name, salary, salary_rank
FROM (
SELECT department, name, salary,
DENSE_RANK() OVER (
PARTITION BY department ORDER BY salary DESC
) AS salary_rank
FROM employees
) t
WHERE salary_rank <= 3;Przykład: drugie najwyższe wynagrodzenie
To najsłynniejsze pytanie rekrutacyjne dotyczące SQL. Solidna odpowiedź wykorzystuje DENSE_RANK, dzięki czemu powtarzające się najwyższe wynagrodzenia nie sprawiają, że dotarcie do właściwej drugiej wartości staje się niemożliwe.
Jeśli trzy osoby zarabiają maksymalną kwotę, DENSE_RANK = 2 nadal poprawnie wskaże kolejne różne wynagrodzenie, podczas gdy ROW_NUMBER = 2 zwróci po prostu inną osobę z najwyższym wynagrodzeniem.
SELECT DISTINCT salary AS second_highest
FROM (
SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS dr
FROM employees
) t
WHERE dr = 2;RANK a DENSE_RANK dla „N-tej najwyższej wartości”
Dlaczego w zadaniach dotyczących N-tej najwyższej wartości należy wybrać DENSE_RANK zamiast RANK? Ponieważ RANK pozostawia luki. Dla wynagrodzeń 100, 100, 90 wartość 90 ma RANK = 3, ale DENSE_RANK = 2.
Jeśli pytanie dotyczy „2. najwyższego różnego wynagrodzenia”, filtrowanie za pomocą RANK = 2 nie zwróci nic, podczas gdy DENSE_RANK = 2 poprawnie zwróci 90. Zawsze należy mapować „N-tą różną wartość” na DENSE_RANK.
-- salaries 100,100,90
-- RANK: 1,1,3 -> WHERE rank = 2 returns NOTHING
-- DENSE_RANK: 1,1,2 -> WHERE dense_rank = 2 returns 90Uwagi dotyczące różnych dialektów
Dobra wiadomość: ROW_NUMBER, RANK i DENSE_RANK są zgodne ze standardem SQL i działają identycznie w PostgreSQL, SQL Server, Oracle, MySQL 8+, BigQuery oraz Snowflake. Opisana powyżej semantyka remisów jest uniwersalna.
Powiązana funkcja, PERCENT_RANK, bazuje na RANK i zwraca względną pozycję z zakresu od 0 do 1 — warto o niej wspomnieć, jeśli rekruter zapyta o ranking percentylowy.
Typowe błędy
Należy uważać na następujące kwestie:
- Użycie
ROW_NUMBERdla „N-tej najwyższej wartości” i pominięcie wierszy objętych remisem. - Użycie
RANK, gdy pytanie dotyczy różnych wartości, a następnie uzyskanie pustego wyniku z powodu luk. - Pominięcie
ORDER BYwewnątrzOVER— bez niego ranking nie ma znaczenia. - Filtrowanie rankingu bezpośrednio w
WHEREzamiast w zapytaniu zewnętrznym.
Szybkie sprawdzenie
Zastosuj zasady dotyczące remisów.
Podsumowanie: luki i brak luk
Może już Pan/Pani natychmiast wybrać właściwą funkcję rankingową:
- ROW_NUMBER: unikalne numery, bez współdzielonych pozycji.
- RANK: remisy zajmują tę samą pozycję, po której występuje luka (1,2,2,4).
- DENSE_RANK: remisy zajmują tę samą pozycję, bez luki (1,2,2,3).
- „N-ta najwyższa różna wartość” →
DENSE_RANK; „N najlepszych wyników z uwzględnieniem remisów” →RANK/DENSE_RANK; „jeden wiersz na pozycję” →ROW_NUMBER.
Następnie: jak faktycznie filtrować wynik funkcji okna, ponieważ nie można tego zrobić w WHERE.
Ucz się SQL dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 30
- Lekcje
- 120
Często zadawane pytania
Czy lekcja „RANK a DENSE_RANK przy remisach” jest bezpłatna?
Tak — pełny tekst „RANK a DENSE_RANK przy remisach” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu SQL Interview Prep, przejdź na CoddyKit PRO. Kurs SQL Interview Prep zawiera 4 lekcji w sumie.
Co nauczysz się w „RANK a DENSE_RANK przy remisach”?
Klasyczne pytanie o numerację z lukami i bez luk, gdy wartości są równe Ćwiczysz SQL Interview Prep z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć SQL Interview Prep?
Nie wymagamy żadnego doświadczenia. SQL Interview Prep w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „RANK a DENSE_RANK przy remisach”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji SQL Interview Prep?
Tak. Każda lekcja SQL Interview Prep zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- OVER, PARTITION BY i ORDER BY
- ROW_NUMBER do unikatowej numeracji
- RANK a DENSE_RANK przy remisach
- Filtrowanie wyniku funkcji okienkowej