web-dev-qa-db-fra.com

RANK SQL () vs ROW_NUMBER ()

Je suis confus au sujet des différences entre ceux-ci. L'exécution du code SQL suivant m'apporte deux ensembles de résultats identiques. Quelqu'un peut-il s'il vous plaît expliquer les différences?

SELECT ID, [Description], RANK()       OVER(PARTITION BY StyleID ORDER BY ID) as 'Rank'      FROM SubStyle
SELECT ID, [Description], ROW_NUMBER() OVER(PARTITION BY StyleID ORDER BY ID) as 'RowNumber' FROM SubStyle
148
dotNET Hobbiest

ROW_NUMBER: Retourne un numéro unique pour chaque ligne commençant par 1. Pour les lignes comportant des valeurs en double, les numéros sont attribués de manière arbitraire.

Rang: Attribue un numéro unique à chaque ligne en commençant par 1, à l'exception des lignes comportant des valeurs en double. Dans ce cas, le même classement est attribué et un vide apparaît dans la séquence pour chaque classement en double.

183
Ritesh

Vous ne verrez la différence que si vous avez des liens dans une partition pour une valeur de commande particulière.

RANK et DENSE_RANK sont déterministes dans ce cas, toutes les lignes ayant la même valeur pour les colonnes de classement et de partitionnement aboutiront au même résultat, alors que ROW_NUMBER affectera de manière arbitraire (non déterministe) un résultat incrémenté aux lignes liées. 

Exemple: (Toutes les lignes ont la même StyleID donc sont dans la même partition et dans cette partition, les 3 premières lignes sont liées quand elles sont ordonnées par ID)

WITH T(StyleID, ID)
     AS (SELECT 1,1 UNION ALL
         SELECT 1,1 UNION ALL
         SELECT 1,1 UNION ALL
         SELECT 1,2)
SELECT *,
       RANK() OVER(PARTITION BY StyleID ORDER BY ID)       AS 'RANK',
       ROW_NUMBER() OVER(PARTITION BY StyleID ORDER BY ID) AS 'ROW_NUMBER',
       DENSE_RANK() OVER(PARTITION BY StyleID ORDER BY ID) AS 'DENSE_RANK'
FROM   T  

Résultats

StyleID     ID       RANK      ROW_NUMBER      DENSE_RANK
----------- -------- --------- --------------- ----------
1           1        1         1               1
1           1        1         2               1
1           1        1         3               1
1           2        4         4               2

Vous pouvez voir que pour les trois lignes identiques incrémentées par ROW_NUMBER, la valeur RANK reste la même, puis passe à 4. DENSE_RANK attribue également le même rang aux trois lignes, mais la valeur distincte suivante se voit attribuer la valeur 2.

270
Martin Smith

Cet article traite d'une relation intéressante entre ROW_NUMBER() et DENSE_RANK() (la fonction RANK() n'est pas traitée spécifiquement). Lorsque vous avez besoin d'une ROW_NUMBER() générée sur une instruction SELECT DISTINCT, la ROW_NUMBER() produira des valeurs distinctes avant qui sont supprimées par le mot clé DISTINCT. Par exemple. cette requête

SELECT DISTINCT
  v, 
  ROW_NUMBER() OVER (ORDER BY v) row_number
FROM t
ORDER BY v, row_number

... peut produire ce résultat (DISTINCT n'a aucun effet):

+---+------------+
| V | ROW_NUMBER |
+---+------------+
| a |          1 |
| a |          2 |
| a |          3 |
| b |          4 |
| c |          5 |
| c |          6 |
| d |          7 |
| e |          8 |
+---+------------+

Considérant que cette requête:

SELECT DISTINCT
  v, 
  DENSE_RANK() OVER (ORDER BY v) row_number
FROM t
ORDER BY v, row_number

... produit ce que vous voulez probablement dans ce cas:

+---+------------+
| V | ROW_NUMBER |
+---+------------+
| a |          1 |
| b |          2 |
| c |          3 |
| d |          4 |
| e |          5 |
+---+------------+

Notez que la clause ORDER BY de la fonction DENSE_RANK() aura besoin de toutes les autres colonnes de la clause SELECT DISTINCT pour fonctionner correctement.

La raison en est que logiquement, les fonctions window sont calculées avant que DISTINCT soit appliqué .

Les trois fonctions en comparaison

Utilisation de la syntaxe standard PostgreSQL/Sybase/SQL (clause WINDOW):

SELECT
  v,
  ROW_NUMBER() OVER (window) row_number,
  RANK()       OVER (window) rank,
  DENSE_RANK() OVER (window) dense_rank
FROM t
WINDOW window AS (ORDER BY v)
ORDER BY v

... tu auras:

+---+------------+------+------------+
| V | ROW_NUMBER | RANK | DENSE_RANK |
+---+------------+------+------------+
| a |          1 |    1 |          1 |
| a |          2 |    1 |          1 |
| a |          3 |    1 |          1 |
| b |          4 |    4 |          2 |
| c |          5 |    5 |          3 |
| c |          6 |    5 |          3 |
| d |          7 |    7 |          4 |
| e |          8 |    8 |          5 |
+---+------------+------+------------+
23
Lukas Eder

Un peu:

Le rang d'une ligne est égal à un plus le nombre de rangs précédant la ligne en question.

Row_number est le rang distinct des rangées, sans aucun écart dans le classement.

http://www.bidn.com/blogs/marcoadf/bidn-blog/379/ranking-functions-row_number-vs-rank-vs-dense_rank-vs-ntile

3
NotMe

Faites également attention à ORDER BY dans PARTITION (la base de données Standard AdventureWorks est utilisée par exemple) lorsque vous utilisez RANK.

SELECT as1.SalesOrderID, as1.SalesOrderDetailID, RANK () OVER (PARTITION BY as1.SalesOrderID ORDER BY as1.SalesOrderID) ranknoequal , RANK () OVER (PARTITION DE as1.SalesOrderID ORDER BY As1.SalesOrderDetailId) ranknodiff FROM Sales.SalesOrderDetail as1 WHERE SalesOrderId = 43659 ORDER BY SalesOrderDetailId;

Donne le résultat:














Mais si change order by to (utilisez OrderQty:

Sélectionnez as1.SalesOrderID, as1.OrderQty, RANK () OVER (PARTITION BY As1.SalesOrderID ORDER BY as1.SalesOrderID) ranknoequal, RANK () OVER (PARTITION BY as1.SalesOrderID ORDER BY as1.OrderQty) rank_orderqty FROM Sales.SalesOrderDetail as1 WHERE SalesOrderId = 43659 ORDER BY Quantité de commande;

Donne:














Remarquez comment le classement change lorsque nous utilisons OrderQty (la seconde table la plus à droite) dans ORDER BY et comment il change lorsque nous utilisons SalesOrderDetailID (la première table la plus à droite) dans ORDER BY. 

0
user2629395

Je n'ai rien fait avec rank, mais j'ai découvert cela aujourd'hui avec row_number ().

select item, name, sold, row_number() over(partition by item order by sold) as row from table_name

Certains numéros de ligne se répèteront, car dans mon cas, chaque nom contient tous les éléments. Chaque article sera commandé par combien ont été vendus.

+--------+------+-----+----+
|glasses |store1|  30 | 1  |
|glasses |store2|  35 | 2  |
|glasses |store3|  40 | 3  |
|shoes   |store2|  10 | 1  |
|shoes   |store1|  20 | 2  |
|shoes   |store3|  22 | 3  |
+--------+------+-----+----+
0
SarahLaMont

Regardez cet exemple.

CREATE TABLE [dbo].#TestTable(
    [id] [int] NOT NULL,
    [create_date] [date] NOT NULL,
    [info1] [varchar](50) NOT NULL,
    [info2] [varchar](50) NOT NULL,
)

Insérer des données

INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (1, '1/1/09', 'Blue', 'Green')
INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (1, '1/2/09', 'Red', 'Yellow')
INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (1, '1/3/09', 'Orange', 'Purple')
INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (2, '1/1/09', 'Yellow', 'Blue')
INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (2, '1/5/09', 'Blue', 'Orange')
INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (3, '1/2/09', 'Green', 'Purple')
INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (3, '1/8/09', 'Red', 'Blue')

Répéter les mêmes valeurs pour 1

INSERT INTO dbo. # TestTable (id, create_date, info1, info2) VALUES (1, '1/1/09', 'Blue', 'Green')

Regardez tous

SELECT * FROM #TestTable

Regardez vos résultats 

SELECT Id,
    create_date,
    info1,
    info2,
    ROW_NUMBER() OVER (PARTITION BY Id ORDER BY create_date DESC) AS RowId,
    RANK() OVER(PARTITION BY Id ORDER BY create_date DESC)    AS [RANK]
FROM #TestTable

Besoin de comprendre les différents

0
sansalk