コマンド道場
ROW_NUMBER / RANK / DENSE_RANK難易度 ★★★★

同額は同順位、次は飛ばす順位づけ

在籍中の社員に給与の高い順で順位を付けてください。給与が同額なら同じ順位とし、その次の順位は飛ばします(1, 2, 2, 4 のように付けます)。列は「順位, 名前, 給与」の順、順位の昇順に並べ、同順位のときは社員番号(shain_id)の小さい順にしてください。

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

製品ごとの対応表(実測)を見る

  • 同順位の次を飛ばすのが rank()、飛ばさず詰めるのが dense_rank()、同額でも別々の番号を振るのが row_number() です。
  • ウィンドウ関数が使えるのは SQLite 3.25 以降・MySQL 8.0 以降です。それより前の環境では相関副問い合わせで代用します。
● 起動中…

この問題で使えるテーブル(名前をタップすると入力できます)

7

NULL
🔑int不可
text不可
int
データを見る(先頭 5 行)
busho_idbusho_nameparent_busho_id
1経営NULL
2開発1
3営業1
4管理1
5基盤2

18

NULL
🔑int不可
text不可
int
int
numeric(10,0)不可
date不可
date
データを見る(先頭 5 行)
shain_idnamebusho_idjoushi_idsalaryhired_ontaishoku_on
1鈴木1NULL9800002014-04-01NULL
2佐藤217200002016-10-01NULL
3田中225200002019-04-01NULL
4中村225300002020-04-01NULL
5小林224450502024-04-01NULL

解説

結論

rank() OVER (ORDER BY salary DESC) です。同額は同順位、次は飛ばします。

★3 つの順位関数の違い(このデータで確かめられます): 給与が同額の社員が 2 人います。・rank() … 1, 2, 3, 4, 5, 6, 6, 8(同額の次を飛ばす。同額が 2 人なら 7 が欠番になる)・dense_rank() … 1, 2, 3, 4, 5, 6, 6, 7(飛ばさない)・row_number() … 1, 2, 3, 4, 5, 6, 7, 8(同額でも別番号。どちらが 6 位になるかは OVER の中の並びだけでは決まらない)「〇位タイ」を表現したいなら rank()、「何段階目か」を知りたいなら dense_rank() です。

★OVER の中と外の ORDER BY は別物です: OVER (ORDER BY salary DESC) は「順位を付ける基準」、いちばん外側の ORDER BY は「結果の並べ方」です。外側を書かないと、順位はついていても表示順はばらばらになりえます。

★ウィンドウ関数は WHERE では使えません: WHERE はウィンドウ関数より先に評価されるためです。「上位 3 位までを表示」のような絞り込みは、いったん派生表や WITH で順位を付けてから、外側で WHERE をかけます。

よくある間違い

①rank / dense_rank / row_number を取り違える。②OVER の中に DESC を書き忘れる。③外側の ORDER BY を省いて並びが不定になる。

根拠(一次情報)