$ man rank
RANK / DENSE_RANK
ウィンドウ関数順位を付ける。同じ値には同じ順位が付く。RANK は次の番号が飛び、DENSE_RANK は飛ばない。
呼び出しの形
RANK() OVER (ORDER BY 式) DENSE_RANK() OVER (ORDER BY 式) RANK() OVER (PARTITION BY 式 ORDER BY 式)
つまずきやすいところ
同順位があると
RANKは番号が飛びます。「1 位, 2 位, 3 位…」と連番になる前提のコードは壊れます。ORDER BYを書かないと順位に意味がなくなります(すべて 1 位になります)。順位を絞り込みたいときは
WHERE r <= 3を同じ階層に書けません。副問い合わせかWITHで一度列にしてから絞ります。
実行例
結果は実際に流したものです。同じ SQL を 自由に打てる画面 で試すと、同じ結果になります。
SELECT name, salary, RANK() OVER (ORDER BY salary DESC) AS r, DENSE_RANK() OVER (ORDER BY salary DESC) AS dr FROM shain ORDER BY r, name
| name | salary | r | dr |
|---|---|---|---|
| 鈴木 | 980000 | 1 | 1 |
| 佐藤 | 720000 | 2 | 2 |
| 山田 | 700000 | 3 | 3 |
| 清水 | 650000 | 4 | 4 |
| 加藤 | 610000 | 5 | 5 |
| 中村 | 530000 | 6 | 6 |
| 伊藤 | 530000 | 6 | 6 |
| 田中 | 520000 | 8 | 7 |
18 行(うち 8 行を表示)
中村と伊藤が同額(530000)です。ここから先で 2 つの列がずれます。
SELECT busho_id, name, salary, RANK() OVER (PARTITION BY busho_id ORDER BY salary DESC) AS r FROM shain ORDER BY busho_id, r
| busho_id | name | salary | r |
|---|---|---|---|
| 1 | 鈴木 | 980000 | 1 |
| 2 | 佐藤 | 720000 | 1 |
| 2 | 中村 | 530000 | 2 |
| 2 | 田中 | 520000 | 3 |
| 2 | 小林 | 445050 | 4 |
| 3 | 山田 | 700000 | 1 |
| 3 | 伊藤 | 530000 | 2 |
| 3 | 高橋 | 480000 | 3 |
18 行(うち 8 行を表示)
説明
RANK は ORDER BY で並べた順に順位を付けます。ROW_NUMBER との違いは、同じ値には同じ順位が付くことです。
同順位のあとの番号の扱いが 2 通りあります。
RANK… 1, 2, 2, 4 … と、同順位の数だけ飛びますDENSE_RANK… 1, 2, 2, 3 … と、飛びません
「3 位が何人いるか分からないが、とにかく上位 3 位まで」という要件なら RANK、「上から 3 段階まで」なら DENSE_RANK です。要件の言葉を、どちらの数え方かに翻訳するところが設計の勘どころになります。
PARTITION BY を付ければ、区切りごとに順位を振り直せます。
ほかの製品でも通るか
主要 7 製品で通用 そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database / IBM Db2
次に読む
関係する関数
根拠にした一次情報
- PostgreSQL 18 マニュアル: ウィンドウ関数(2026-09-02 確認)