ROW_NUMBER()
は、SQLのwindow関数の1つ。ROW_NUMBER
関数を使用すると、結果セットの行に一意の連番を付与することができます。実際のデータには影響を与えませんが、結果として表示されるデータに番号を付けるのに便利です。
SELECT ROW_NUMBER() OVER() as rownum, * FROM sample_data;
参考 SELECT文の基本
ROW_NUMBER()
は、結果セットの行に連番を付与する関数。ORDER BY
を使って、特定の順序で番号を付けることが可能。PARTITION BY
を使うと、指定した列の値ごとに番号付けをリセットすることができる。
参考 window関数とは?
このページではROW_NUMBER
関数の基本を1からわかりやすく初心者向けに解説します。
プログラマーやシステムエンジニアを目指す方であれば知らないと恥ずかしい基本知識です。是非最後までご覧ください。
ROW_NUMBER関数とは?
ROW_NUMBER()
はSQLのウィンドウ関数の1つで、データセットの各行に一意の連続する番号(行番号)を付与するときに使用します。主に、行に番号をつけたい場面や特定の条件でのランキングをつけたい場面などで使用されます。
実際のデータに変更を加えるわけではなく、クエリの結果として表示されるデータに一時的に番号を付けるためのものです。
ROW_NUMBER関数:構文ルール
ROW_NUMBER() OVER ( [PARTITION BY 列名1, 列名2, ... ] [ORDER BY 列名A [ASC | DESC], ... ] )
PARTITION BY
- オプション(任意):特定の列を基にしてデータをグループ分けし、そのグループごとに行番号を1から付け直します。
ORDER BY
- オプション(任意):行番号を付与する際の順序を指定するためのもので、指定した列の順に従って行番号が付与されます。
サンプルコード1 studentsテーブル
/* サンプルデータ |----|---------|-------| | id | name | score | |----|---------|-------| | 1 | Alice | 85 | | 2 | Bob | 90 | | 3 | Charlie | 85 | | 4 | David | 92 | | 5 | Eve | 88 | |----|---------|-------| */ SELECT ROW_NUMBER() OVER(ORDER BY score, name) as rownum, id, name, score FROM students; /* 実行結果 scoreの昇順(低いスコアから高いスコアへ)に基づいて行番号が付与された結果が得られる |--------|----|---------|-------| | rownum | id | name | score | |--------|----|---------|-------| | 1 | 1 | Alice | 85 | | 2 | 3 | Charlie | 85 | | 3 | 5 | Eve | 88 | | 4 | 2 | Bob | 90 | | 5 | 4 | David | 92 | |--------|----|---------|-------| */
サンプルコード2 employeesテーブル
/* サンプルデータ: employees |----|---------|------------|--------| | id | name | department | salary | |----|---------|------------|--------| | 1 | Alice | HR | 5000 | | 2 | Bob | Sales | 5500 | | 3 | Charlie | HR | 5200 | | 4 | David | Sales | 5300 | | 5 | Eve | Sales | 6000 | |----|---------|------------|--------| */ -- 部署(department)ごとに給与(salary)の昇順で行番号を付けるクエリ SELECT ROW_NUMBER() OVER(PARTITION BY department ORDER BY salary) as rownum, id, name, department, salary FROM employees; /* 実行結果 |--------|----|---------|------------|--------| | rownum | id | name | department | salary | |--------|----|---------|------------|--------| | 1 | 1 | Alice | HR | 5000 | | 2 | 3 | Charlie | HR | 5200 | | 1 | 4 | David | Sales | 5300 | | 2 | 2 | Bob | Sales | 5500 | | 3 | 5 | Eve | Sales | 6000 | |--------|----|---------|------------|--------| */
このクエリの実行結果を見ると、PARTITION BY
の効果により、部署ごとに行番号が1から始まっています。そして、その中でORDER BY
により給与の昇順に行番号が付けられていることがわかります。
このように、PARTITION BY
とORDER BY
を組み合わせることで、特定のカテゴリやグループ内での順序付けを行うことができます。
ROW_NUMBER関数を利用する際の注意点
最後にROW_NUMBER関数を利用する際の注意点について補足しておきます。
この関数はよく利用する関数でもあるので、特に以下の点を押さえておくことが重要です。
1. 一意性の確保
ROW_NUMBER()
関数は、指定した順序で行に一意の番号を付与します。しかし、同じ値を持つ行(つまり順序が同じ行)が複数存在する場合、それらの行の順序はデータベースエンジンに依存するため、必ずしも一定ではありません。
/* サンプルデータ: students |----|---------|-------| | id | name | score | |----|---------|-------| | 1 | Alice | 85 | | 2 | Bob | 85 | | 3 | Charlie | 90 | |----|---------|-------| */ SELECT ROW_NUMBER() OVER(ORDER BY score) as rownum, id, name, score FROM students; /* 実行結果 (順序は不確定) |--------|----|---------|-------| | rownum | id | name | score | |--------|----|---------|-------| | 1 | ? | ? | 85 | | 2 | ? | ? | 85 | | 3 | 3 | Charlie | 90 | |--------|----|---------|-------| */
このクエリでは、AliceとBobのscore
が同じであるため、それらに付与される行番号の順序は不確定です。
一意の順序を確保するためには、ORDER BY
句に複数の列を追加することで、一意性を強制することができます。以下のように、score
の後にid
を追加してみます。
/* サンプルデータ: students |----|---------|-------| | id | name | score | |----|---------|-------| | 1 | Alice | 85 | | 2 | Bob | 85 | | 3 | Charlie | 90 | |----|---------|-------| */ SELECT ROW_NUMBER() OVER(ORDER BY score, id) as rownum, id, name, score FROM students; /* 実行結果 (一意の順序が確保される) |--------|----|---------|-------| | rownum | id | name | score | |--------|----|---------|-------| | 1 | 1 | Alice | 85 | | 2 | 2 | Bob | 85 | | 3 | 3 | Charlie | 90 | |--------|----|---------|-------| */
このクエリでは、score
が同じ場合、次にid
の順番を考慮するため、一意の順序が確保されます。
2. 性能に関する注意点
大量のデータを扱う場合、ROW_NUMBER()
関数の計算には時間がかかることがあります。特にPARTITION BY
やORDER BY
を使った複雑なソートや分割を行う際には、パフォーマンスの低下が考えられます。
適切なインデックスの作成やクエリの最適化を検討することが重要です。
3. ROW_NUMBER() vs RANK() vs DENSE_RANK()
ROW_NUMBER()
以外にも、RANK()
やDENSE_RANK()
などの関数があります。これらの関数も行に番号を付与するのに使用されますが、同じ値を持つ行に対する取り扱いが異なります。
使用する関数を選択する際には、それぞれの動作を理解して、目的に合った関数を選択することが重要です。
4. バージョンやデータベースの種類による違い
ROW_NUMBER()
関数は、多くのリレーショナルデータベースシステムでサポートされていますが、使用できるバージョンや具体的な動作、性能などにはデータベースの種類やバージョンによる違いがあります。
公式のドキュメントやリファレンスを確認することをおすすめします。
現在のスキルに今一つ満足できていないシステムエンジニア/プログラマーの方へ。
SQLやデータベースの仕組みを1から学習したい方(学び直したい方)向けに、現役エンジニア達のスキルを結集して 完全無料 のSQL教材を作成しました。是非この機会にブックマークを!
読者料典 【完全無料】SQL:初心者向け学習ロードマップ ←こちらから!