【SQLメモ】RANK / ROW_NUMBER / DENSE_RANK の違いを整理

さだちかの実務ログ

「rankとrow_numberってどう違うんだっけ?この状況ではどっちを使うべき…?」
と分からなくなって何度調べたことか笑

特にウィンドウ関数は、日常的に使っていても挙動を忘れがち。
そこで今回は、RANKROW_NUMBERDENSE_RANK の3つの違いについて、できるだけシンプルに・すぐ思い出せるように整理してみました。

同じように毎回調べている方の助けになればうれしいです。

1. まずは結論:違いをざっくり整理

関数名重複値への対応順位の飛び方ユースケース例
ROW_NUMBER無視(毎行ユニーク)順位は飛ばない一意に順位をつけたいとき(サンプル抽出など)
RANK同順位をつける順位が飛ぶスポーツの順位、コンテストの結果など
DENSE_RANK同順位をつける順位は飛ばない商品の売上ランクなどで連番にしたいとき

2. 実際のクエリで違いを見てみる

WITH sample_data AS (
SELECT 'A' AS item, 100 AS sales UNION ALL
SELECT 'B', 200 UNION ALL
SELECT 'C', 200 UNION ALL
SELECT 'D', 150
)

SELECT
item,
sales,
RANK() OVER (ORDER BY sales DESC) AS rank,
ROW_NUMBER() OVER (ORDER BY sales DESC) AS row_number,
DENSE_RANK() OVER (ORDER BY sales DESC) AS dense_rank
FROM sample_data;

▼ 実行結果

itemsalesrankrow_numberdense_rank
B200111
C200121
D150332
A100443

3. ざっくり覚えるための語感まとめ(暗記用)

  • ROW_NUMBER: 行ごとに番号ふる。毎行違う → ユニークな番号。
  • RANK: 順位をふるけど同率があると飛ばす。
  • DENSE_RANK: 同率あっても詰めて連番でふる。

4. よくある使い方と注意点

✅ ROW_NUMBER の典型例

特定条件の最新データを1件だけ取得したいとき。
ユーザーごとの最新の購入日や購入内容など知りたい時に使えるので、これが一番使う!

SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS rn
FROM access_logs
)
WHERE rn = 1

✅ RANK や DENSE_RANK の落とし穴

  • 順位が欲しいだけなら RANK or DENSE_RANK
  • でも、ORDER BY の方向(ASC/DESC)を間違うと、順位が逆になるので注意!

Comment