SQL RANK()とROW_NUMBER()の比較


189

これらの違いについて混乱しています。次のSQLを実行すると、2つの重要な結果セットが取得されます。誰かが違いを説明できますか?

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

回答:


221

ROW_NUMBER: 1から始まる各行に一意の番号を返します。重複する値を持つ行の場合、番号は任意に割り当てられます。

ランク: 1から始まる各行に一意の番号を割り当てます。ただし、重複する値を持つ行は例外です。この場合、同じランキングが割り当てられ、重複する各ランクのシーケンスにギャップが表示されます。


324

パーティション内に特定の順序付け値のタイがある場合にのみ、違いがわかります。

RANKそして DENSE_RANK、一方、この場合には、決定論的であり、順序付け及び分割列の両方に対して同じ値を持つすべての行が、同じ結果に終わるであろうROW_NUMBER任意の(非決定論的に)関連付けられた行にインクリメント結果を割り当てます。

例:(すべての行は同じであるStyleIDため、同じパーティションにあり、そのパーティション内で最初の3行はによって順序付けされたときに関連付けられます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  

戻り値

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

同一の3つの行のROW_NUMBER増分では、RANK値は同じままで、に跳ね上がり4ます。DENSE_RANKまた、3つの行すべてに同じランクを割り当てますが、次の個別の値には値2が割り当てられます。


26
素晴らしい!... DENSE_RANKについて言及してくれてありがとう
Sandeep Thomas

7
素晴らしい例をありがとう。ROW_NUMBER()の方がはるかに適切であったときに、誤ってRANK()関数を使用していたことに気づきました。
Ales Potocnik Hahonina 2014年

2
真剣に、これは素晴らしいです。
Matt Felzani 2016

35

この記事では、間の興味深い関係をカバーROW_NUMBER()し、DENSE_RANK()RANK()機能は特に処理されていません)。あなたが発生した場合には必要ROW_NUMBER()SELECT DISTINCT声明、ROW_NUMBER()個別の値が生成されます前に、彼らがすることによって除去されているDISTINCTキーワード。たとえば、このクエリ

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

...この結果が生成される可能性があります(DISTINCT影響なし):

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

一方、このクエリ:

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

...この場合におそらく必要なものを生成します。

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

関数の句が正しく機能するORDER BYには、句のDENSE_RANK()他のすべての列が必要SELECT DISTINCTです。

これは、論理的には、ウィンドウ関数がDISTINCT適用される前に計算されるためです。

3つの機能すべての比較

PostgreSQL / Sybase / SQL標準構文(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

...あなたは得るでしょう:

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

1
ROW_NUMBERとDENSE_RANKはどちらも、distinctが適用される前に値を生成します。実際には、DISTINCTが適用される前に、すべてのランキング関数または任意の関数が結果を生成します。
Thanasis Ioannidis

1
@ThanasisIoannidis:もちろんです。SQLオペレーションの実際の順序を
Lukas Eder

3

かなり少し:

行のランクは、1に、問題の行の前に来るランクの数を足したものです。

Row_numberは、ランキングにギャップのない、行の個別のランクです。

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


ああ、これは私が欠けていたものだと思います-> Row_numberは行の明確なランクであり、ランキングにギャップはありません。
dotNET Hobbiest 2011年

1

パーティション句のない単純なクエリ:

select 
    sal, 
    RANK() over(order by sal desc) as Rank,
    DENSE_RANK() over(order by sal desc) as DenseRank,
    ROW_NUMBER() over(order by sal desc) as RowNumber
from employee 

出力:

    --------|-------|-----------|----------
    sal     |Rank   |DenseRank  |RowNumber
    --------|-------|-----------|----------
    5000    |1      |1          |1
    3000    |2      |2          |2
    3000    |2      |2          |3
    2975    |4      |3          |4
    2850    |5      |4          |5
    --------|-------|-----------|----------

0

この例を見てください。

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

データを挿入

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')

1に対して同じ値を繰り返す

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

すべて見る

SELECT * FROM #TestTable

結果を見てください

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

違いを理解する必要があります


-1

また、RANKを使用する場合は、PARTYTIONのORDER BY(たとえば、標準のAdventureWorks dbが使用される)に注意してください。

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

結果を与える:

SalesOrderID SalesOrderDetailID rank_same_as_partition rank_salesorderdetailid
43659 1 1 1
43659 2 1 2
43659 3 1 3
43659 4 1 4
43659 5 1 5
43659 6 1 6
43659 7 1 7
43659 8 1 8
43659 9 1 9
43659 10 1 10
43659 11 1 11
43659 12 1 12

しかし、順序をに変更する場合(OrderQtyを使用:

SELECT 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 OrderQty;

与える:

SalesOrderID OrderQty rank_salesorderid rank_orderqty
43659 1 1 1
43659 1 1 1
43659 1 1 1
43659 1 1 1
43659 1 1 1
43659 1 1 1
43659 2 1 7
43659 2 1 7
43659 3 1 9
43659 3 1 9
43659 4 1 11
43659 6 1 12

ORDER BYでOrderQty(右端の2番目のテーブル)を使用するとランクがどのように変化し、ORDER BYでSalesOrderDetailID(右端の最初のテーブル)を使用するとランクが変化するかに注意してください。


-1

ランクについては何もしていませんが、row_number()を使用してこれを発見しました。

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

私の場合、各名前がすべてのアイテムを保持しているため、これにより、行番号が繰り返されることになります。各商品は販売数順に並べられます。

+--------+------+-----+----+
|glasses |store1|  30 | 1  |
|glasses |store2|  35 | 2  |
|glasses |store3|  40 | 3  |
|shoes   |store2|  10 | 1  |
|shoes   |store1|  20 | 2  |
|shoes   |store3|  22 | 3  |
+--------+------+-----+----+
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.