Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Come funziona DENSE_RANK() in SQL Server

In SQL Server, il DENSE_RANK() La funzione restituisce il rango di ogni riga all'interno della partizione di un set di risultati. Il rango di una riga è uno più il numero di ranghi distinti che precedono la riga.

Questa funzione è simile a RANK() , ma senza le lacune nei valori di classifica che possono verificarsi con RANK() quando esistono pareggi nel set di risultati.

Sintassi

La sintassi è questa:

DENSE_RANK ( ) OVER ( [  ] < order_by_clause > )

è facoltativo. Divide il set di risultati prodotto dal FROM clausola in partizioni a cui viene applicata la funzione. Se non specificato, tutte le righe del set di risultati della query vengono trattate come un unico gruppo.

è obbligatorio. Determina l'ordine in cui la funzione si applica alle righe in una partizione.

Nota che il OVER La clausola normalmente accetta una , ma quell'argomento non può essere utilizzato con questa funzione.

Esempio 1 – Utilizzo di base

Ecco un esempio di base che mostra l'utilizzo di DENSE_RANK() funzione:

SELECT
  AlbumId,
  AlbumName,
  ArtistId,
  DENSE_RANK() OVER (ORDER BY ArtistId ASC) 'Rank'
FROM Albums;

Risultato:

+-----------+--------------------------+------------+--------+
| 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          | 2      |
| 19        | All Night Wrong          | 3          | 3      |
| 20        | The Sixteen Men of Tain  | 3          | 3      |
| 12        | Big Swing Face           | 4          | 4      |
| 4         | Ziltoid the Omniscient   | 5          | 5      |
| 5         | Casualties of Cool       | 5          | 5      |
| 6         | Epicloud                 | 5          | 5      |
| 3         | Singing Down the Lane    | 6          | 6      |
| 16        | Long Lost Suitcase       | 7          | 7      |
| 17        | Praise and Blame         | 7          | 7      |
| 18        | Along Came Jones         | 7          | 7      |
| 11        | No Sound Without Silence | 9          | 8      |
| 21        | Yo Wassup                | 9          | 8      |
| 22        | Busted                   | 9          | 8      |
| 13        | Blue Night               | 12         | 9      |
| 14        | Eternity                 | 12         | 9      |
| 15        | Scandinavia              | 12         | 9      |
+-----------+--------------------------+------------+--------+

Guarda ArtistId e Classifica colonne. Il grado aumenta ogni volta che l'ID artista aumenta. Questo perché sto ordinando per ArtistId, quindi ogni nuovo artista riceverà un nuovo grado.

La classifica rimane la stessa per ogni artista, indipendentemente dal numero di righe che contengono lo stesso ArtistId, perché i risultati sono ordinati in base a quella colonna. Ad esempio, cinque righe contengono lo stesso ArtistId e quindi contengono anche lo stesso rango. In altre parole, sono tutti a pari merito per il rango 1.

In molte righe, il rango sembra essere identico a ArtistId, ma questa è solo una coincidenza. Succede che ArtistId è un IDENTITY colonna che inizia da 1 e aumenta di 1, che è anche ciò che è RANK() fa. Tuttavia, vedrai che non sono identici su tutte le righe. Ad esempio, ArtistId salta da 7 a 9, ma la classifica aumenta semplicemente da 7 a 8 e, da quel momento in poi, entrambe le colonne contengono valori diversi.

Esempio 2 – Partizioni

Puoi anche dividere i risultati in partizioni. Quando lo fai, il rango viene calcolato rispetto a ciascuna partizione (quindi ricomincia da capo a ogni nuova partizione).

Esempio:

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

Risultato:

+---------+--------------------------+------------+--------+
| 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          | 2      |
| Pop     | Long Lost Suitcase       | 7          | 1      |
| Pop     | Praise and Blame         | 7          | 1      |
| Pop     | Along Came Jones         | 7          | 1      |
| Pop     | No Sound Without Silence | 9          | 2      |
| Pop     | Blue Night               | 12         | 3      |
| Pop     | Eternity                 | 12         | 3      |
| Pop     | Scandinavia              | 12         | 3      |
| 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          | 2      |
| Rock    | Ziltoid the Omniscient   | 5          | 3      |
| Rock    | Casualties of Cool       | 5          | 3      |
| Rock    | Epicloud                 | 5          | 3      |
+---------+--------------------------+------------+--------+

In questo caso partizione per Genere. Ciò fa sì che ogni riga venga classificata solo rispetto alle altre righe nella stessa partizione. Quindi ogni partizione fa ripartire il valore della classifica da 1.

Esempio 3:un esempio di tabellone segnapunti

Ecco un possibile caso d'uso per visualizzare il grado all'utente.

SELECT  
  Player,
  Score,
  DENSE_RANK() OVER (ORDER BY Score Desc) 'Rank'
FROM Scoreboard;

Risultato:

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

Tieni presente che qualsiasi risultato in parità non influirà sui ranghi successivi. In altre parole, non ci saranno lacune nel valore della classifica.

Questo è probabilmente spiegato meglio con un esempio:

SELECT  
  Player,
  Score,
  DENSE_RANK() OVER (ORDER BY Score Desc) 'Rank'
FROM Scoreboard;

Risultato:

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

In questo caso Lisa e Bart sono in parità al numero 1. Poi arriva Burns al numero 2 (anche se è la terza persona).

Se preferisci che Burns sia al 3° posto in questo caso (e Meg al 4° e così via), usa il RANK() funzione invece.

Esempio 4 – Sostituzione di DENSE_RANK() con RANK()

Ecco di nuovo lo stesso esempio, tranne che questa volta uso RANK() :

SELECT  
  Player,
  Score,
  RANK() OVER (ORDER BY Score Desc) 'Rank'
FROM Scoreboard;

Risultato:

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