Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como RANK() funciona no SQL Server


No SQL Server, o RANK() A função retorna a classificação de cada linha dentro da partição de um conjunto de resultados. A classificação de uma linha é um mais o número de classificações que vêm antes da linha.


Sintaxe


A sintaxe fica assim:
RANK ( ) OVER ( [ partition_by_clause ] order_by_clause )

partition_by_clause é opcional. Ele divide o conjunto de resultados produzido pelo FROM cláusula em partições às quais a função é aplicada. Se não for especificado, a função trata todas as linhas do conjunto de resultados da consulta como um único grupo.

order_by_clause É necessário. Ele determina a ordem dos dados antes que a função seja aplicada.

Observe que o OVER cláusula normalmente aceita uma rows_or_range_clause , mas esse argumento não pode ser usado com o RANK() função.

Exemplo 1 – Uso básico


Aqui está um exemplo básico mostrando o uso do RANK() função:
SELECT
  AlbumId,
  AlbumName,
  ArtistId,
  RANK() OVER (ORDER BY ArtistId ASC) 'Rank'
FROM Albums;

Resultado:
+-----------+--------------------------+------------+--------+
| 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     |
+-----------+--------------------------+------------+--------+

Nosso foco principal é o ArtistId e Classificação colunas. Podemos ver que a classificação aumenta cada vez que o ArtistId aumenta. Isso ocorre porque estou solicitando por ArtistId e, portanto, cada novo artista receberá uma nova classificação.

Quando olhamos para o Classificação coluna, podemos ver alguns empates. Ou seja, algumas linhas compartilham a mesma classificação. Isso é esperado, porque estou ordenando por ArtistId e alguns valores de ArtistId estão em mais de uma linha.

Essas linhas vinculadas são ótimas para demonstrar como RANK() funciona. Como mencionado, ele aumenta em um mais o número de classificações que vieram antes dele. As linhas amarradas fazem com que as lacunas apareçam nos valores de classificação (ou seja, elas nem sempre aumentam em 1). No exemplo acima, existem algumas lacunas. A primeira é onde vai de 1 a 6. Depois outra quando vai de 7 a 9, e assim por diante.

Se você não quiser essas lacunas, use DENSE_RANK() , que funciona da mesma maneira, exceto sem lacunas. A classificação densa é calculada como um mais o número de distintos valores de classificação que vêm antes dessa linha.

Exemplo 2 – Partições


Você também pode dividir os resultados em partições. Quando você faz isso, a classificação é calculada em relação a cada partição (assim ela começa novamente com cada nova partição).

Exemplo:
SELECT
  Genre,
  AlbumName,
  ArtistId,
  RANK() OVER (PARTITION BY Genre ORDER BY ArtistId ASC) 'Rank'
FROM Albums
INNER JOIN Genres 
ON Albums.GenreId = Genres.GenreId;

Resultado:
+---------+--------------------------+------------+--------+
| 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      |
+---------+--------------------------+------------+--------+

Neste caso eu particiono por Gênero. Isso faz com que cada linha seja classificada apenas em relação às outras linhas na mesma partição. Portanto, cada partição faz com que o valor de classificação comece em 1 novamente.

Exemplo 3 – Exemplo de placar


Aqui está um possível caso de uso para exibir a classificação para o usuário.
SELECT  
  Player,
  Score,
  RANK() OVER (ORDER BY Score Desc) 'Rank'
FROM Scoreboard;

Resultado:
+----------+---------+--------+
| 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      |
+----------+---------+--------+

No entanto, esteja ciente de que quaisquer resultados empatados resultarão em lacunas nos valores de classificação.

Aqui está o que acontece se Lisa de repente igualar a pontuação de Bart:
SELECT  
  Player,
  Score,
  RANK() OVER (ORDER BY Score Desc) 'Rank'
FROM Scoreboard;

Resultado:
+----------+---------+--------+
| 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      |
+----------+---------+--------+

Neste caso, ninguém está classificado no número 2, porque os dois primeiros jogadores estão empatados no ranking 1.

Como mencionado, se você precisar eliminar lacunas como esta, use DENSE_RANK() .

Exemplo 4 – Substituindo RANK() por DENSE_RANK()


Aqui está o mesmo exemplo novamente, exceto que desta vez eu uso DENSE_RANK() :
SELECT  
  Player,
  Score,
  DENSE_RANK() OVER (ORDER BY Score Desc) 'Rank'
FROM Scoreboard;

Resultado:
+----------+---------+--------+
| 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      |
+----------+---------+--------+