ROW_NUMBER do unikatowej numeracji
Przypisywanie deterministycznego numeru wiersza w każdej partycji
ROW_NUMBER do unikatowej numeracji to bezpłatna lekcja Coding Interview Prep na CoddyKit. To lekcja 2 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 Coding Interview Prep, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Coding Interview Prep zawiera 4 lekcji w sumie.
Gwarancje ROW_NUMBER
ROW_NUMBER() przypisuje każdemu wierszowi w obrębie jego partycji unikalną liczbę całkowitą bez luk, rozpoczynając od 1 i stosując kolejność zdefiniowaną przez okno ORDER BY. Żadne dwa wiersze nigdy nie otrzymają tego samego numeru, nawet gdy ich wartości sortowania są identyczne.
Ta unikalność jest właśnie powodem, dla którego rekruterzy sięgają po tę funkcję przy rozwiązywaniu problemów typu „wybierz jeden wiersz na grupę” oraz problemów z deduplikacją. Pozostałe funkcje rankingowe (RANK, DENSE_RANK) nie gwarantują unikalności w przypadku remisów.
Minimalne zapytanie z ROW_NUMBER
Najprostsza postać numeruje cały zestaw wynikowy w wybranej kolejności. ROW_NUMBER zawsze wymaga ORDER BY wewnątrz OVER — bez niego numeracja byłaby przypadkowa, a większość silników odrzuca takie użycie lub wyświetla ostrzeżenie.
W tym przykładzie najpóźniej zatrudniony pracownik otrzyma numer wiersza 1, jeśli data zatrudnienia zostanie uporządkowana malejąco.
SELECT
name,
hire_date,
ROW_NUMBER() OVER (ORDER BY hire_date DESC) AS rn
FROM employees;Numerowanie w obrębie partycji
Dodaj PARTITION BY, aby niezależnie numerować wiersze wewnątrz każdej grupy. Licznik rozpoczyna się od 1 przy każdej nowej wartości partycji.
W tym przykładzie każdy dział otrzymuje własną sekwencję 1, 2, 3 uporządkowaną według wynagrodzenia. Najlepiej zarabiająca osoba w każdym dziale otrzymuje numer 1 — to podstawa wzorca top-N-per-group.
SELECT
department,
name,
salary,
ROW_NUMBER() OVER (
PARTITION BY department
ORDER BY salary DESC
) AS dept_rn
FROM employees;ROW_NUMBER a remisy: remisów nie ma
To kluczowa kwestia podczas rozmowy kwalifikacyjnej: gdy dwa wiersze mają takie same wartości sortowania, ROW_NUMBER nadal nadaje im różne numery. To, który z nich otrzyma niższy numer, jest niedeterministyczne, chyba że zostanie dodana kolumna rozstrzygająca remis.
RANKnadałby remisującym wierszom tę samą rangę.ROW_NUMBERarbitralnie wybiera kolejność między nimi.
Aby wyniki były powtarzalne, zawsze dodawaj unikalny klucz rozstrzygający remis do ORDER BY.
SELECT
name,
salary,
ROW_NUMBER() OVER (
ORDER BY salary DESC, employee_id -- employee_id breaks ties deterministically
) AS rn
FROM employees;Zasada deterministycznego rozstrzygania remisów
Jeśli ORDER BY nie definiuje ścisłego porządku (żadna kombinacja kolumn nie jest unikalna), numeracja wierszy może zmieniać się między uruchomieniami, nawet dla tych samych danych. Rekruterzy celowo umieszczają tę pułapkę w pytaniach dotyczących paginacji i „najnowszego rekordu”.
Zasada praktyczna: dodaj klucz główny lub inną unikalną kolumnę jako ostatni klucz sortowania, gdy wynik musi być stabilny.
-- Unstable: many rows can share the same created_at
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC)
-- Stable: id guarantees a single deterministic winner
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC, id DESC)Przykład: najnowsze zamówienie każdego klienta
To standardowe pytanie: „Zwróć najnowsze zamówienie każdego klienta”. Ponumeruj zamówienia każdego klienta według malejącej daty, a następnie zachowaj rn = 1 w zapytaniu zewnętrznym.
Ponieważ ROW_NUMBER gwarantuje dokładnie jeden wiersz z numerem 1 w każdej partycji, otrzymują Państwo dokładnie jeden wiersz na klienta — bez duplikatów, nawet jeśli dwa zamówienia mają ten sam znacznik czasu (rozstrzyga to dodatkowy klucz).
SELECT customer_id, order_id, order_date, amount
FROM (
SELECT
customer_id, order_id, order_date, amount,
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY order_date DESC, order_id DESC
) AS rn
FROM orders
) t
WHERE rn = 1;Przykład: usuwanie duplikatów wierszy
ROW_NUMBER to najwygodniejsze narzędzie do deduplikacji. Podziel dane na partycje według kolumn definiujących duplikat, uporządkuj je według reguły wyboru, a następnie zachowaj rn = 1.
W tym przykładzie traktujemy wiersze z tym samym adresem e-mail jako duplikaty i zachowujemy ten utworzony najwcześniej. Wszystko, co ma rn > 1, jest duplikatem, który można usunąć lub pominąć.
SELECT id, email, created_at
FROM (
SELECT
id, email, created_at,
ROW_NUMBER() OVER (
PARTITION BY email
ORDER BY created_at ASC, id ASC
) AS rn
FROM users
) t
WHERE rn = 1;ROW_NUMBER do paginacji
Zanim OFFSET/FETCH stały się powszechnie dostępne, do paginacji używano ROW_NUMBER; nadal stosuje się je w SQL Server i wielu zadaniach ETL. Ponumeruj wiersze w stabilnej kolejności, a następnie odfiltruj zakres numerów w zapytaniu zewnętrznym.
Uwaga dotycząca rozmów kwalifikacyjnych: paginacja jest poprawna tylko wtedy, gdy kolejność jest deterministyczna — w przeciwnym razie ten sam wiersz może pojawić się na dwóch stronach albo zostać całkowicie pominięty.
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY created_at, id) AS rn
FROM articles
) t
WHERE rn BETWEEN 21 AND 40; -- page 2, 20 per pagePrzypisywanie sekwencji w celu ponownego uporządkowania danych
Czasami potrzebny jest po prostu indeks sekwencyjny, na przykład do ponownego ponumerowania wierszy po sortowaniu, utworzenia etykiet 1..N lub połączenia w pary wierszy z wygenerowaną serią. ROW_NUMBER zastosowane do wybranej kolejności tworzy czystą, gęstą sekwencję bez luk.
W ten sposób można również nadać dowolnemu nieuporządkowanemu zbiorowi stabilną pozycję na potrzeby późniejszego złączenia.
SELECT
ROW_NUMBER() OVER (ORDER BY score DESC, player_id) AS leaderboard_position,
player_id,
score
FROM scores;ROW_NUMBER a COUNT dla „N-tego wiersza”
Gdy pytanie dotyczy „trzeciego najnowszego zamówienia” lub „drugiego wiersza”, należy sięgnąć po ROW_NUMBER i odfiltrować dokładną wartość w zapytaniu zewnętrznym. Ponieważ numeracja jest unikalna, rn = 3 zwraca dokładnie jeden wiersz.
Dla porównania, jeśli potrzebują Państwo drugiej odrębnej wartości (np. drugiego najwyższego wynagrodzenia z uwzględnieniem remisów), ROW_NUMBER jest niewłaściwym narzędziem — potrzebny jest DENSE_RANK, omówiony w następnej lekcji.
SELECT order_id, order_date
FROM (
SELECT order_id, order_date,
ROW_NUMBER() OVER (ORDER BY order_date DESC, order_id DESC) AS rn
FROM orders
) t
WHERE rn = 3; -- exactly the 3rd most recent orderPodsumowanie pułapek
Podczas rozmowy kwalifikacyjnej należy pamiętać o następujących zasadach:
ROW_NUMBERjest zawsze unikalny i pozbawiony luk w obrębie partycji.- Wymaga
ORDER BYwOVER; bez unikalnego klucza rozstrzygającego remisy wyniki są niedeterministyczne w przypadku remisów. - Nie można filtrować go w
WHERE— należy umieścić go w podzapytaniu/CTE. - Używaj go do wybierania jednego wiersza na grupę, deduplikacji i paginacji; używaj
DENSE_RANK, gdy remisujące wiersze powinny otrzymać ten sam numer.
Szybki test
Jak ROW_NUMBER obsługuje wiersze z taką samą wartością w ORDER BY?
Podsumowanie: deterministyczne numerowanie
ROW_NUMBER jest narzędziem do unikalnej, pozbawionej luk numeracji w obrębie partycji. Nauczyli się Państwo:
- Numerować całe zbiory oraz grupy w obrębie partycji.
- Dodawać unikalny klucz rozstrzygający remisy, aby uzyskiwać deterministyczne i powtarzalne wyniki.
- Rozwiązywać problemy dotyczące najnowszego wiersza dla klucza, deduplikacji, paginacji i N-tego wiersza, filtrując
rnw zapytaniu zewnętrznym.
Następnie zobaczą Państwo, jak RANK i DENSE_RANK celowo nadają remisującym wierszom ten sam numer oraz czym różni się ich zachowanie w przypadku luk.
Często zadawane pytania
Czy lekcja „ROW_NUMBER do unikatowej numeracji” jest bezpłatna?
Tak — pełny tekst „ROW_NUMBER do unikatowej numeracji” 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 Coding Interview Prep, przejdź na CoddyKit PRO. Kurs Coding Interview Prep zawiera 4 lekcji w sumie.
Co nauczysz się w „ROW_NUMBER do unikatowej numeracji”?
Przypisywanie deterministycznego numeru wiersza w każdej partycji Ćwiczysz Coding 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ąć Coding Interview Prep?
Nie wymagamy żadnego doświadczenia. Coding 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 2 z 4.
Ile czasu zajmuje lekcja „ROW_NUMBER do unikatowej numeracji”?
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 Coding Interview Prep?
Tak. Każda lekcja Coding 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