コマンド道場

$ man row-number

ROW_NUMBER

ウィンドウ関数

並べた順に 1, 2, 3 … と通し番号を振る。同じ値でも必ず別の番号になる。

呼び出しの形

ROW_NUMBER() OVER (ORDER BY 式)
ROW_NUMBER() OVER (PARTITION BY 式 ORDER BY 式)

つまずきやすいところ

  • 同じ値でも別の番号になります。同順位を同じ番号にしたいなら RANK です。

  • ORDER BY に一意になる列を足さないと、同じ値どうしの順番が実行のたびに変わりえます。結果を再現したいなら必ず足してください。

  • WHERE の中で ROW_NUMBER() を直接使うことはできません。ウィンドウ関数は WHERE より後に評価されるためで、副問い合わせや WITH で一度列にしてから絞ります。

実行例

結果は実際に流したものです。同じ SQL を 自由に打てる画面 で試すと、同じ結果になります。

給与の高い順に通し番号を振る
SELECT name, salary, ROW_NUMBER() OVER (ORDER BY salary DESC, shain_id) AS bangou FROM shain ORDER BY bangou
namesalarybangou
鈴木9800001
佐藤7200002
山田7000003
清水6500004
加藤6100005
中村5300006
伊藤5300007
田中5200008

18(うち 8 行を表示)

中村と伊藤は同額(530000)ですが、ROW_NUMBER なので別の番号になります。

部署ごとに 1 から振り直す
SELECT busho_id, name, salary, ROW_NUMBER() OVER (PARTITION BY busho_id ORDER BY salary DESC, shain_id) AS junban FROM shain ORDER BY busho_id, junban
busho_idnamesalaryjunban
1鈴木9800001
2佐藤7200001
2中村5300002
2田中5200003
2小林4450504
3山田7000001
3伊藤5300002
3高橋4800003

18(うち 8 行を表示)

説明

ROW_NUMBER は、ORDER BY で並べた順に重複しない通し番号を振ります。RANK と違い、同じ値でも同じ番号にはなりません

PARTITION BY を付けると、その区切りごとに 1 から振り直します。「部署ごとに給与の高い順で 1 番、2 番…」といった使い方です。

⚠️ 同じ値が並んでいるとき、どちらが先になるかは決まりません。毎回同じ結果にしたいなら、ORDER BY salary DESC, shain_id のように必ず一意になる列を最後に足してください。これを忘れると、同じ問い合わせなのに実行のたびに順番が変わることがあります。

「各グループの先頭 n 件」を取るときは、ROW_NUMBER を副問い合わせで振ってから外側で WHERE 番号 <= n と絞るのが定石です。

ほかの製品でも通るか

主要 7 製品で通用 そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database / IBM Db2

製品ごとの対応表(根拠つき)を見る

次に読む

関係する関数

根拠にした一次情報