В SQL Server, RANK()
функцията връща ранга на всеки ред в рамките на дяла на набор от резултати. Рангът на ред е едно плюс броя на ранговете, които идват преди реда.
Синтаксис
Синтаксисът е така:
RANK ( ) OVER ( [ partition_by_clause ] order_by_clause )
раздел_по_клауза е по избор. Той разделя резултатния набор, произведен от FROM
клауза в дялове, към които се прилага функцията. Ако не е посочено, функцията третира всички редове от набора от резултати от заявката като една група.
клауза_по_порядък изисква се. Той определя реда на данните преди прилагането на функцията.
Имайте предвид, че OVER
клаузата обикновено приема клауза_rows_or_range_clause , но този аргумент не може да се използва с RANK()
функция.
Пример 1 – Основна употреба
Ето основен пример, показващ използването на RANK()
функция:
SELECT AlbumId, AlbumName, ArtistId, RANK() OVER (ORDER BY ArtistId ASC) 'Rank' FROM Albums;
Резултат:
+-----------+--------------------------+------------+--------+ | AlbumId | AlbumName | ArtistId | Rank | |-----------+--------------------------+------------+--------| | 1 | Powerslave | 1 | 1 | | 7 | Somewhere in Time | 1 | 1 | | 8 | Piece of Mind | 1 | 1 | | 9 | Killers | 1 | 1 | | 10 | No Prayer for the Dying | 1 | 1 | | 2 | Powerage | 2 | 6 | | 19 | All Night Wrong | 3 | 7 | | 20 | The Sixteen Men of Tain | 3 | 7 | | 12 | Big Swing Face | 4 | 9 | | 4 | Ziltoid the Omniscient | 5 | 10 | | 5 | Casualties of Cool | 5 | 10 | | 6 | Epicloud | 5 | 10 | | 3 | Singing Down the Lane | 6 | 13 | | 16 | Long Lost Suitcase | 7 | 14 | | 17 | Praise and Blame | 7 | 14 | | 18 | Along Came Jones | 7 | 14 | | 11 | No Sound Without Silence | 9 | 17 | | 21 | Yo Wassup | 9 | 17 | | 22 | Busted | 9 | 17 | | 13 | Blue Night | 12 | 20 | | 14 | Eternity | 12 | 20 | | 15 | Scandinavia | 12 | 20 | +-----------+--------------------------+------------+--------+
Основният ни фокус е ArtistId и Ранг колони. Можем да видим, че рангът се увеличава всеки път, когато ArtistId се увеличава. Това е така, защото поръчвам по ArtistId и така всеки нов изпълнител ще получи нов ранг.
Когато погледнем Ранг колона, можем да видим доста връзки. Тоест, доста редове споделят един и същи ранг. Това може да се очаква, защото поръчвам по ArtistId и някои стойности на ArtistId са в повече от един ред.
Тези обвързани редове са чудесни за демонстриране как RANK()
върши работа. Както споменахме, той се увеличава с едно плюс броя на ранговете, които са дошли преди него. Свързаните редове причиняват появата на пропуски в стойностите на класирането (т.е. те не винаги се увеличават с 1). В горния пример има доста пропуски. Първият е мястото, където преминава от 1 до 6. След това още едно, когато преминава от 7 до 9, и така нататък.
Ако не искате тези пропуски, използвайте DENSE_RANK()
, който работи по същия начин, освен без пропуски. Плътният ранг се изчислява като едно плюс броя на отличителните ранг стойности, които идват преди този ред.
Пример 2 – Дялове
Можете също да разделите резултатите на дялове. Когато направите това, рангът се изчислява спрямо всеки дял (така че започва отново с всеки нов дял).
Пример:
SELECT Genre, AlbumName, ArtistId, RANK() OVER (PARTITION BY Genre ORDER BY ArtistId ASC) 'Rank' FROM Albums INNER JOIN Genres ON Albums.GenreId = Genres.GenreId;
Резултат:
+---------+--------------------------+------------+--------+ | Genre | AlbumName | ArtistId | Rank | |---------+--------------------------+------------+--------| | Country | Singing Down the Lane | 6 | 1 | | Country | Yo Wassup | 9 | 2 | | Country | Busted | 9 | 2 | | Jazz | All Night Wrong | 3 | 1 | | Jazz | The Sixteen Men of Tain | 3 | 1 | | Jazz | Big Swing Face | 4 | 3 | | Pop | Long Lost Suitcase | 7 | 1 | | Pop | Praise and Blame | 7 | 1 | | Pop | Along Came Jones | 7 | 1 | | Pop | No Sound Without Silence | 9 | 4 | | Pop | Blue Night | 12 | 5 | | Pop | Eternity | 12 | 5 | | Pop | Scandinavia | 12 | 5 | | Rock | Powerslave | 1 | 1 | | Rock | Somewhere in Time | 1 | 1 | | Rock | Piece of Mind | 1 | 1 | | Rock | Killers | 1 | 1 | | Rock | No Prayer for the Dying | 1 | 1 | | Rock | Powerage | 2 | 6 | | Rock | Ziltoid the Omniscient | 5 | 7 | | Rock | Casualties of Cool | 5 | 7 | | Rock | Epicloud | 5 | 7 | +---------+--------------------------+------------+--------+
В този случай разделя по Жанр. Това кара всеки ред да се класира само спрямо другите редове в същия дял. Така че всеки дял кара стойността на класирането да започне отново от 1.
Пример 3 – Пример за табло
Ето възможен случай на използване за показване на ранга на потребителя.
SELECT Player, Score, RANK() OVER (ORDER BY Score Desc) 'Rank' FROM Scoreboard;
Резултат:
+----------+---------+--------+ | Player | Score | Rank | |----------+---------+--------| | Bart | 2010 | 1 | | Burns | 1270 | 2 | | Meg | 1030 | 3 | | Marge | 990 | 4 | | Lisa | 710 | 5 | | Ned | 666 | 6 | | Apu | 350 | 7 | | Homer | 1 | 8 | +----------+---------+--------+
Имайте предвид обаче, че всички равни резултати ще доведат до пропуски в стойностите на класирането.
Ето какво се случва, ако Лиза изведнъж съвпадне с резултата на Барт:
SELECT Player, Score, RANK() OVER (ORDER BY Score Desc) 'Rank' FROM Scoreboard;
Резултат:
+----------+---------+--------+ | Player | Score | Rank | |----------+---------+--------| | Lisa | 2010 | 1 | | Bart | 2010 | 1 | | Burns | 1270 | 3 | | Meg | 1030 | 4 | | Marge | 990 | 5 | | Ned | 666 | 6 | | Apu | 350 | 7 | | Homer | 1 | 8 | +----------+---------+--------+
В този случай никой не се класира на номер 2, тъй като първите двама играчи са изравнени на ранг 1.
Както споменахме, ако трябва да премахнете пропуски като тази, използвайте DENSE_RANK()
.
Пример 4 – Замяна на RANK() с DENSE_RANK()
Ето отново същия пример, освен че този път използвам DENSE_RANK()
:
SELECT Player, Score, DENSE_RANK() OVER (ORDER BY Score Desc) 'Rank' FROM Scoreboard;
Резултат:
+----------+---------+--------+ | Player | Score | Rank | |----------+---------+--------| | Lisa | 2010 | 1 | | Bart | 2010 | 1 | | Burns | 1270 | 2 | | Meg | 1030 | 3 | | Marge | 990 | 4 | | Ned | 666 | 5 | | Apu | 350 | 6 | | Homer | 1 | 7 | +----------+---------+--------+