SQLのRANK関数とは?順位付けウィンドウ関数を実務で完全解説
CONTENTS
SQLで「売上ランキングを出したい」「部門ごとのTOP3を取得したい」「重複データの最新1件だけを残したい」といった要件に直面したことはないでしょうか。
その際に欠かせないのが、RANK をはじめとした「順位付けウィンドウ関数」です。
しかし実際の現場では、
RANKとROW_NUMBERの違いが曖昧- 同順位があると件数が増えて困る
PARTITION BYの使いどころが分からないWHERE rank <= 3が動かない- DBごとに微妙に挙動が違う
といったポイントでつまずくケースが非常に多くあります。
この記事では、SQLの順位付け関数について、
- 基礎知識
- 実務での使い分け
- よくある失敗
- DB方言の注意点
- 実践的なTOP-N抽出
- パフォーマンス観点
- 実務ユースケース
まで含めて、現場レベルで体系的に解説します。
単なる構文紹介ではなく、「実際にどう設計し、どう使い分けるべきか」が理解できる内容を目指しています。
SQLの構文や使い分けを理解した後は、
どの学習サイトで、どの順番でSQLを身につけていくかも重要になります。
学習全体の進め方を整理したい方は、こちらも参考にしてみてください。
→ SQL学習サイト徹底比較|初心者から上級者まで迷わない学習ロードマップ完全版また、これからSQL学習を始める方や基礎を固めたい方は、以下の記事も役立ちます。
→ 【初心者向け】SQL練習のはじめ方~おすすめ学習サイトと効率的な勉強法~
SQLの順位付けウィンドウ関数とは
順位付けウィンドウ関数とは、SQLの検索結果に対して「順位」や「連番」を付与する機能です。
通常の集計関数(SUMやAVG)は行をまとめますが、ウィンドウ関数は「元の行を保持したまま計算結果を追加できる」のが大きな特徴です。
例えば以下のような要件に使われます。
- 売上ランキング
- 部門別順位
- 上位3名抽出
- 最新データのみ取得
- 重複データ除去
- 顧客ランク分類
- 上位25%ユーザー抽出
近年の分析SQLでは必須級の知識といえます。
RANK関数とは
RANK() は、SQLの結果セットに順位を付ける代表的なウィンドウ関数です。
最も重要な特徴は、
同点の場合は同順位になり、その分だけ次順位が飛ぶ
という点です。
例えばスコアが以下の場合:
| score |
|---|
| 100 |
| 90 |
| 90 |
| 80 |
RANKの結果は:
| score | rank |
|---|---|
| 100 | 1 |
| 90 | 2 |
| 90 | 2 |
| 80 | 4 |
となります。
「3位」が存在しない点が特徴です。
これはスポーツ順位表などでも使われる自然な順位表現です。
RANK関数の基本構文
RANK() OVER (
ORDER BY score DESC
)
グループごとに順位を付ける場合:
RANK() OVER (
PARTITION BY department_id
ORDER BY score DESC
)
OVER句の役割
順位付け関数では OVER 句が非常に重要です。
ここで以下を定義します。
- どの単位で順位付けするか
- どの順番で順位付けするか
ORDER BYは実質必須
順位を定義する以上、何を基準に順位付けするかが必要です。
例えば:
ORDER BY sales DESC
なら売上が高い順になります。
逆に:
ORDER BY defect_rate ASC
なら不良率が低い順になります。
実務では、
- 高いほど良い指標
- 低いほど良い指標
を混同する事故が非常に多いため注意が必要です。
PARTITION BYでグループ別順位を作る
実務では「全体順位」より「グループ内順位」のほうが頻出します。
例えば:
- 部門別売上順位
- 店舗別ランキング
- カテゴリ別人気順位
- 月別順位
などです。
その際に使うのが PARTITION BY です。
部門別ランキングの例
SELECT
employee_name,
department_id,
sales,
RANK() OVER(
PARTITION BY department_id
ORDER BY sales DESC
) AS rank_no
FROM sales_table;
これにより、
- 営業部の中で1位
- 開発部の中で1位
という形で順位がリセットされます。
PARTITION設計は分析結果を左右する
実務ではここが非常に重要です。
例えば:
PARTITION BY store_id
なのか、
PARTITION BY store_id, sales_month
なのかで分析結果は大きく変わります。
ランキング設計では、
「誰と誰を比較したいのか」
を先に決めることが重要です。
RANK・DENSE_RANK・ROW_NUMBERの違い
順位付け関数で最も混乱しやすいポイントです。
RANK:同順位あり+欠番あり
1,2,2,4
特徴:
- 同順位あり
- 欠番あり
- スポーツ順位向き
DENSE_RANK:同順位あり+欠番なし
1,2,2,3
特徴:
- 同順位あり
- 欠番なし
- UI表示向き
ROW_NUMBER:必ず一意連番
1,2,3,4
特徴:
- 同順位なし
- 行数固定
- 最新1件取得向き
- 重複除去向き
実務での使い分け早見表
| 要件 | 推奨関数 |
|---|---|
| 同順位を許可したい | RANK |
| 欠番を避けたい | DENSE_RANK |
| 必ずN件返したい | ROW_NUMBER |
| 重複排除したい | ROW_NUMBER |
| セグメント分けしたい | NTILE |
ROW_NUMBERは実務で非常に重要
現場では ROW_NUMBER() の使用頻度が非常に高いです。
特に:
- 最新レコード取得
- 重複除去
- 代表行抽出
- N件固定抽出
で多用されます。
最新1件だけ取得する例
WITH latest_data AS (
SELECT
*,
ROW_NUMBER() OVER(
PARTITION BY customer_id
ORDER BY updated_at DESC
) AS rn
FROM customer_history
)
SELECT *
FROM latest_data
WHERE rn = 1;
これは実務で頻出するパターンです。
NTILEで分位分析を行う
NTILE() は順位ではなく「グループ分割」を行います。
四分位を作る例
NTILE(4) OVER(
ORDER BY sales DESC
)
これで:
- 上位25%
- 上位50%
- 下位25%
などを簡単に分類できます。
NTILEの代表的ユースケース
- RFM分析
- 優良顧客抽出
- 上位ユーザー分析
- 広告効果分析
- セグメント分け
マーケティングSQLで非常によく使われます。
TOP-N抽出の正しい書き方
初心者が最もハマりやすいポイントです。
NG例
SELECT
*,
RANK() OVER(ORDER BY sales DESC) AS rnk
FROM sales_table
WHERE rnk <= 3;
これは多くのDBでエラーになります。
理由は:
- WHEREが先
- SELECTが後
というSQL評価順序 때문です。
正しい書き方(CTE)
WITH ranked AS (
SELECT
*,
RANK() OVER(
ORDER BY sales DESC
) AS rnk
FROM sales_table
)
SELECT *
FROM ranked
WHERE rnk <= 3;
実務ではこの形が定石です。
「TOP3」と「3件」は別要件
これは非常に重要です。
RANK
WHERE rank <= 3
→ 同率3位を含む
→ 件数増加あり
ROW_NUMBER
WHERE row_num <= 3
→ 必ず3件
要件確認時に必ず整理すべきポイントです。
タイブレークを必ず設計する
実務で見落とされがちな重要ポイントです。
例えば:
ROW_NUMBER() OVER(
ORDER BY score DESC
)
だけだと、同点時の順番が不安定になります。
結果:
- 実行ごとに順位が変わる
- UI表示が揺れる
- テストが不安定
という問題が起きます。
正しいタイブレーク例
ROW_NUMBER() OVER(
ORDER BY score DESC, id ASC
)
一意キーを最後に入れるのが定石です。
NULLの扱いに注意
ランキングではNULLが事故要因になりやすいです。
DBごとにNULL順が違う
例えば:
- PostgreSQL
- MySQL
- SQL Server
ではNULLの既定順位が異なります。
そのため重要ランキングでは:
COALESCE(score, 0)
などで明示処理するのが安全です。
NULLを除外する方法
WHERE score IS NOT NULL
NULLを順位対象外にするケースも多いです。
実務で頻出するユースケース
売上ランキング
RANK() OVER(
ORDER BY sales DESC
)
店舗別TOP3
RANK() OVER(
PARTITION BY store_id
ORDER BY sales DESC
)
最新履歴取得
ROW_NUMBER() OVER(
PARTITION BY user_id
ORDER BY updated_at DESC
)
重複除去
ROW_NUMBER() OVER(
PARTITION BY email
ORDER BY created_at DESC
)
上位顧客分類
NTILE(4) OVER(
ORDER BY purchase_amount DESC
)
パフォーマンス観点で知っておくべきこと
順位付け関数は便利ですが、データ量が大きいと重くなります。
特に:
- ORDER BY
- PARTITION BY
はソートコストが高いため注意が必要です。
実務で重要な最適化ポイント
インデックスを貼る
INDEX(department_id, sales)
など。
PARTITIONを細かくしすぎない
グループが多すぎると逆にコストが増えることがあります。
必要列だけ取得する
SELECT *
は避ける。
先にWHEREで絞る
ランキング前に対象件数を減らす。
DB別の違いと注意点
MySQL
MySQLは8.0以降で本格対応です。
公式:MySQL公式ドキュメント(Window Functions)
PostgreSQL
PostgreSQLはウィンドウ関数が非常に強力です。
公式:PostgreSQL公式ドキュメント(Window Functions)
よくある実務トラブル
ランキング結果が毎回変わる
原因:
- タイブレーク不足
対策:
ORDER BY score DESC, id ASC
TOP3なのに5件返る
原因:
- RANKで同率3位を含んでいる
対策:
- ROW_NUMBERを使う
- 要件確認を行う
順位がおかしい
原因:
- ASC/DESC逆
- NULL混入
- 文字列ソート
特に文字列型数値は危険です。
CAST(score AS INTEGER)
などで型を明示します。
学習におすすめの進め方
順位付け関数は、
- 覚える
- 実行する
- 比較する
の順番で理解が深まります。
おすすめは:
- 同じデータに対して
- RANK
- DENSE_RANK
- ROW_NUMBER
- NTILE
を全部同時に出して比較することです。
かなり理解が早まります。
まとめ
SQLの順位付けウィンドウ関数は、分析SQL・業務システム・データ基盤のいずれでも非常に重要な知識です。
特に重要なのは以下です。
- RANKは同順位+欠番あり
- DENSE_RANKは欠番なし
- ROW_NUMBERは一意連番
- NTILEは分位分析向き
- TOP-N抽出はCTE化が定石
- タイブレークは必須
- NULLと型に注意
- 「N位まで」と「N件まで」は別要件
このあたりを正しく理解しているだけで、SQL実装の品質は大きく向上します。
また、順位付け関数は単なるSQLテクニックではなく、
- データ分析
- BI
- ダッシュボード
- マーケティング分析
- ETL
- バックエンド開発
など、さまざまな現場で活用される重要技術です。
実際の業務データで手を動かしながら学ぶことで、理解は一気に深まります。
もし「SQLをもっと実務レベルで使いこなしたい」「データ分析やバックエンド開発を強みにしたい」と感じているなら、こうした技術を日常的に扱う環境に身を置くことも大きな成長につながります。
私たちも、SQL・データ活用・Web開発を重視したチームづくりを進めており、技術への探究心を持つ仲間を探しています。
学習意欲が高い方や、実務でさらにSQLスキルを伸ばしたい方は、ぜひ今後のキャリア選択の参考にしてみてください。
学んだSQLを、実務で使えるスキルにしたい方へ
本記事ではSQLの基本的な考え方や使い方を解説しましたが、
「実務で使えるレベルまで身につけたい」と感じた方も多いのではないでしょうか。
SQLは、文法を理解するだけでなく、
- どんなデータ構造で使われるのか
- どんなクエリが現場で求められるのか
を意識して学ぶことで、実践力が大きく変わります。
そうした「実務を見据えたSQL学習」を進めたい方には、
完全無料で学べるプログラミングスクール ZeroCode PLUS という選択肢もあります。
- SQLを含むWeb・データベース系スキルを体系的に学べる
- 未経験者でも実務を意識したカリキュラム
- 受講料・教材費がかからない完全無料の学習環境
- 完全オンラインでスキマ学習
※学習内容や進め方を確認するだけでもOKです