※メモの中で出てくる人物名は仮名です。たまたま同性同名の方がいらっしゃいましたらごめんなさい。
目次
RANKとDENSE_RANKとROW_NUMBERの振る舞い
RANKとDENSE_RANKとROW_NUMBERはそれぞれ似ているけどちょっとだけ違うので違いをメモしておきます。
データ
以下のようなデータを持つテーブルUser
があるとします。
Name | Age | Score |
---|---|---|
川村 千治 | 39 | 70 |
北島 永寿 | 43 | 80 |
永田 祐美 | 27 | 80 |
三上 なつみ | 18 | 75 |
野中 玲奈 | 32 | 100 |
Scoreについて、RANK
、DENSE_RANK
、ROW_NUMBER
をそれぞれ取得すると以下のようになります。
SQL
SELECT [Name] ,[Age] ,[Score] ,RANK() OVER(ORDER BY Score) AS RANK ,DENSE_RANK() OVER(ORDER BY Score) AS DENSE_RANK ,ROW_NUMBER() OVER(ORDER BY Score) AS ROW_NUMBER FROM [dbo].[User]
取得結果
Name | Age | Score | RANK | DENSE_RANK | ROW_NUMBER |
---|---|---|---|---|---|
川村 千治 | 39 | 70 | 1 | 1 | 1 |
北島 永寿 | 43 | 80 | 3 | 3 | 3 |
永田 祐美 | 27 | 80 | 3 | 3 | 4 |
三上 なつみ | 18 | 75 | 2 | 2 | 2 |
野中 玲奈 | 32 | 100 | 5 | 4 | 5 |
それぞれは以下のような特徴がある。
RANK
は同率があった場合順位は同じになり、その次の順位は飛ばします。- 上記の例だと、3位が2名いるため、4位が飛ばされています。
DENSE_RANK
も同率があった場合は順位は同じになりますが、その次の順位は飛ばしません。- 上記の例では、野中さんが4位となっています。
ROW_NUMBER
は、同率があっても同じ順位にはならず、出現順でカウントします。- (注意) 出現順は不定なので、上記の例では、たとえば北島さんと永田さんは2名ともスコアは80で順位はひっくり返ることもあります。
- ちゃんと順序付けしたい場合は、OVER句のORDER BYできちんと指定する必要があります。
- 例) OVER(ORDER BY Score, Age) …スコアで並べ替えた後、同率ならAgeでも並べ替えるため、順位は一意に決まる。
- ちゃんと順序付けしたい場合は、OVER句のORDER BYできちんと指定する必要があります。
- (注意) 出現順は不定なので、上記の例では、たとえば北島さんと永田さんは2名ともスコアは80で順位はひっくり返ることもあります。
PARTITION BY句で区切って順位付けする
RANKとDENSE_RANKとROW_NUMBERの振る舞いで使ったテーブルをちょっと加工して、
以下のようなデータを持つテーブルUser
を準備します。
Name | Age | Score | Class |
---|---|---|---|
川村 千治 | 39 | 70 | A |
永田 祐美 | 27 | 80 | A |
野中 玲奈 | 32 | 100 | A |
増田 保平 | 22 | 50 | B |
上原 さゆみ | 27 | 70 | B |
浅井 れいや | 33 | 80 | B |
竹中 沙耶香 | 24 | 60 | C |
三上 なつみ | 20 | 60 | C |
緒方 利浩 | 18 | 60 | C |
北島 永寿 | 43 | 80 | C |
このデータについて、Class別に順位付けしたい場合、以下のようにOVER句の中で、PARTITION BY
で区切りたい列を指定します。
SQL
SELECT [Name] ,[Age] ,[Score] ,[Class] ,RANK() OVER(PARTITION BY Class ORDER BY Score) AS RANK ,DENSE_RANK() OVER(PARTITION BY Class ORDER BY Score) AS DENSE_RANK ,ROW_NUMBER() OVER(PARTITION BY Class ORDER BY Score, Age DESC) AS ROW_NUMBER FROM [dbo].[User] ORDER BY [Class], [Score]
取得結果
Name | Age | Score | Class | RANK | DENSE_RANK | ROW_NUMBER |
---|---|---|---|---|---|---|
川村 千治 | 39 | 70 | A | 1 | 1 | 1 |
永田 祐美 | 27 | 80 | A | 2 | 2 | 2 |
野中 玲奈 | 32 | 100 | A | 3 | 3 | 3 |
増田 保平 | 22 | 50 | B | 1 | 1 | 1 |
上原 さゆみ | 27 | 70 | B | 2 | 2 | 2 |
浅井 れいや | 33 | 80 | B | 3 | 3 | 3 |
竹中 沙耶香 | 24 | 60 | C | 1 | 1 | 1 |
三上 なつみ | 20 | 60 | C | 1 | 1 | 2 |
緒方 利浩 | 18 | 60 | C | 1 | 1 | 3 |
北島 永寿 | 43 | 80 | C | 4 | 2 | 4 |
- 結果として、Classごとの順位付けした結果が取得されます。
- 上記例のROW_NUMBERは、OVER句内のORDER BYの2番目でAgeにDESCで指定しているので、ClassがCの竹中さん、三上さん、緒方さんは年齢の上の人の方からROW_NUMBERが振られます。