sql >> Base de Datos >  >> RDS >> Sqlserver

Cómo funciona RANK() en SQL Server

En SQL Server, el RANK() La función devuelve el rango de cada fila dentro de la partición de un conjunto de resultados. El rango de una fila es uno más el número de rangos que vienen antes de la fila.

Sintaxis

La sintaxis es así:

RANK ( ) OVER ( [ partition_by_clause ] order_by_clause )

partición_por_cláusula es opcional. Divide el conjunto de resultados producido por FROM cláusula en particiones a las que se aplica la función. Si no se especifica, la función trata todas las filas del conjunto de resultados de la consulta como un solo grupo.

order_by_clause es requerido. Determina el orden de los datos antes de aplicar la función.

Tenga en cuenta que OVER cláusula normalmente acepta una rows_or_range_clause , pero ese argumento no se puede usar con RANK() función.

Ejemplo 1:uso básico

Aquí hay un ejemplo básico que muestra el uso de RANK() función:

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

Nuestro enfoque principal es el ArtistId y Clasificación columnas Podemos ver que el rango aumenta cada vez que aumenta el ArtistId. Esto se debe a que ordeno por ID de artista, por lo que cada nuevo artista obtendrá una nueva clasificación.

Cuando miramos el Rank columna, podemos ver bastantes empates. Es decir, bastantes filas comparten el mismo rango. Esto es de esperar, porque estoy ordenando por ArtistId y algunos valores de ArtistId están en más de una fila.

Estas filas vinculadas son excelentes para demostrar cómo RANK() obras. Como se mencionó, se incrementa en uno más el número de rangos anteriores. Las filas empatadas hacen que aparezcan espacios en los valores de clasificación (es decir, no siempre aumentan en 1). En el ejemplo anterior, hay bastantes lagunas. El primero es donde va del 1 al 6. Luego otro cuando va del 7 al 9, y así sucesivamente.

Si no desea estos espacios, use DENSE_RANK() , que funciona de la misma manera excepto sin espacios. El rango denso se calcula como uno más el número de distintos clasifique los valores que vienen antes de esa fila.

Ejemplo 2:Particiones

También puede dividir los resultados en particiones. Cuando hace esto, el rango se calcula contra cada partición (por lo que comienza de nuevo con cada nueva partición).

Ejemplo:

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

En este caso divido por Género. Esto hace que cada fila solo se clasifique frente a las otras filas en la misma partición. Entonces, cada partición hace que el valor de clasificación comience de nuevo en 1.

Ejemplo 3:un ejemplo de marcador

Aquí hay un posible caso de uso para mostrar el rango al usuario.

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

Sin embargo, tenga en cuenta que cualquier resultado empatado generará brechas en los valores de clasificación.

Esto es lo que sucede si Lisa de repente iguala la puntuación 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      |
+----------+---------+--------+

En este caso, nadie ocupa el puesto número 2, porque los dos primeros jugadores están empatados en el puesto 1.

Como se mencionó, si necesita eliminar espacios como este, use DENSE_RANK() .

Ejemplo 4:reemplazar RANK() con DENSE_RANK()

Aquí está el mismo ejemplo de nuevo, excepto que esta vez 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      |
+----------+---------+--------+