Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

  1. トップページ
  2. SQL辞典
  3. ROW_NUMBER / RANK / DENSE_RANK

ROW_NUMBER / RANK / DENSE_RANK

ウィンドウ関数を使って各行に連番や順位を付与する関数です。同順位の扱いが3つの関数で異なります。

構文
-- ROW_NUMBER: 重複なしの連番を付与します。
ROW_NUMBER() OVER ([PARTITION BY グループ列] ORDER BY 並び順列)

-- RANK: 同順位の次の番号をスキップします。
RANK() OVER ([PARTITION BY グループ列] ORDER BY 並び順列)

-- DENSE_RANK: 同順位があっても番号をスキップしません。
DENSE_RANK() OVER ([PARTITION BY グループ列] ORDER BY 並び順列)
構文一覧
関数概要
ROW_NUMBER()同値の行があっても重複しない一意の連番を付与します。
RANK()同順位の行が複数ある場合、同じ順位を付与し、次の番号をスキップします(1,2,2,4 など)。
DENSE_RANK()同順位の行が複数あっても次の番号をスキップしません(1,2,2,3 など)。
サンプルコード
-- 給与の降順で3種類の順位を同時に表示します。
SELECT
    社員名,
    部署名,
    給与,
    ROW_NUMBER() OVER (ORDER BY 給与 DESC) AS 連番,
    RANK()       OVER (ORDER BY 給与 DESC) AS 順位_RANK,
    DENSE_RANK() OVER (ORDER BY 給与 DESC) AS 順位_DENSE
FROM 社員
ORDER BY 給与 DESC;

-- 部署ごとに給与順位を付けて、各部署の上位2名を取得します。
SELECT 社員名, 部署名, 給与, 部署内順位
FROM (
    SELECT
        社員名,
        部署名,
        給与,
        RANK() OVER (PARTITION BY 部署名 ORDER BY 給与 DESC) AS 部署内順位
    FROM 社員
) AS ranked
WHERE 部署内順位 <= 2;
実行結果
-- 3種類の順位の違い(給与530000が2人いる場合)。
社員名     | 給与    | 連番 | 順位_RANK | 順位_DENSE
-----------+---------+------+-----------+-----------
鈴木 花子  | 620000  | 1    | 1         | 1
山田 太郎  | 530000  | 2    | 2         | 2
佐藤 三郎  | 530000  | 3    | 2         | 2
田中 恵    | 420000  | 4    | 4         | 3
高橋 一郎  | 380000  | 5    | 5         | 4

-- 部署ごとの上位2名。
社員名     | 部署名   | 給与    | 部署内順位
-----------+----------+---------+-----------
鈴木 花子  | 技術部   | 620000  | 1
佐藤 三郎  | 技術部   | 530000  | 2
山田 太郎  | 営業部   | 480000  | 1
田中 恵    | 営業部   | 320000  | 2
データベース別の書き方

『ROW_NUMBER()』『RANK()』『DENSE_RANK()』は MySQL(8.0以降)・PostgreSQL・Oracle・SQL Server・SQLite(3.25以降)で共通して使用できます。

-- 給与の降順で3種類の順位を表示します(主要データベース共通)。
SELECT
    社員名,
    部署名,
    給与,
    ROW_NUMBER() OVER (ORDER BY 給与 DESC) AS 連番,
    RANK()       OVER (ORDER BY 給与 DESC) AS 順位_RANK,
    DENSE_RANK() OVER (ORDER BY 給与 DESC) AS 順位_DENSE
FROM 社員
ORDER BY 給与 DESC;
概要

3つの関数の違いは同順位の扱いです。『ROW_NUMBER()』は常に一意の連番を振るため、同じ値でも異なる番号になります。どの行が先になるかはDBの実装依存です。

『RANK()』と『DENSE_RANK()』は同じ値に同じ順位を付けますが、次の番号の扱いが異なります。スポーツの成績表では RANK(2位が2人いたら次は4位)、段位・級の体系では DENSE_RANK(2位が2人いても次は3位)が適しています。

「上位N位を取得する」には派生テーブル(またはCTE)でまず順位を計算し、外側のWHEREで絞り込む方法を使います。ウィンドウ関数の結果はWHEREで直接フィルタできないためです。ウィンドウ関数の基本構文は『OVER / PARTITION BY』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。