SQL ORACLEのROWNUMで行番号を取得する際の注意点
Oracleで行番号を取得する際の基本的な考え方と注意点を紹介します。
行番号はROWNUMで取得することができます。注意しなければならないのは、ORDER BYでソートする場合です。ORDER BYはSELECT句でROWNUMを採番した後に行われるため、例えば下記のようなSQLを実行した場合、行番号も含めてソートされてしまいます。
SELECT
ROWNUM 行番号
,T1.社員コード
,T1.社員名
FROM
社員マスタ T1
ORDER BY T1.社員コード| 行番号 | 社員コード | 社員名 |
|---|---|---|
| 5 | 1 | テスト社員1 |
| 33 | 2 | テスト社員2 |
| 672 | 3 | テスト社員3 |
| 17 | 4 | テスト社員4 |
| 14 | 5 | テスト社員5 |
なので、社員コードでソートして上位5件を取得したい場合、下記のようなSQLでは正しく取得することができません。
SELECT
ROWNUM 行番号
,T1.社員コード
,T1.社員名
FROM
社員マスタ T1
WHERE
ROWNUM BETWEEN 1 AND 5
ORDER BY T1.社員コード| 行番号 | 社員コード | 社員名 |
|---|---|---|
| 5 | 1 | テスト社員1 |
| 1 | 24 | テスト社員24 |
| 2 | 243 | テスト社員243 |
| 4 | 467 | テスト社員467 |
| 3 | 589 | テスト社員589 |
なぜなら、WHERE句で指定しているROWNUMはORDER BYでソートする前の行番号だからです。
社員コードでソートして取得したデータに対して1行目から行番号を振りたい場合は、下記のように副問い合わせを利用します。
そしてその行番号に対してWHERE句で条件を指定すれば、上位10件を正しく取得することができます。
SELECT
ROWNUM 行番号
,T1.社員コード
,T1.社員名
FROM (
SELECT
T1.社員コード
,T1.社員名
FROM
社員マスタ T1
ORDER BY T1.社員コード
) T1
WHERE
ROWNUM BETWEEN 1 AND 5| 行番号 | 社員コード | 社員名 |
|---|---|---|
| 1 | 1 | テスト社員1 |
| 2 | 2 | テスト社員2 |
| 3 | 3 | テスト社員3 |
| 4 | 4 | テスト社員4 |
| 5 | 5 | テスト社員5 |
しかし、まだ問題があります。ページング処理などで6件~10件のデータを取得したい場合、WHERE ROWNUM BETWEEN 6 AND 10としても正しく取得することができません。
WHERE句にROWNUMの条件を指定して絞り込むと、SELECT句で採番したROWNUMがまた変わって、そうするとWHERE句のROWNUMで絞り込むデータも変わって...といった感じで、正しく取得することができません。(この理由は個人的な勝手なイメージです。正しく取得できないちゃんとした理由はありますが、難しくて混乱してしまうのでここでは説明しません。)
正しく取得するためにはさらに副問い合わせをして、採番した行番号に対してWHERE句で絞り込みを行うようにします。
SELECT
T1.行番号
,T1.社員コード
,T1.社員名
FROM (
SELECT
ROWNUM 行番号
T1.社員コード
,T1.社員名
FROM (
SELECT
T1.社員コード
,T1.社員名
FROM
社員マスタ T1
ORDER BY T1.社員コード
) T1
) T1
WHERE
T1.行番号 BETWEEN 6 AND 10| 行番号 | 社員コード | 社員名 |
|---|---|---|
| 6 | 6 | テスト社員6 |
| 7 | 7 | テスト社員7 |
| 8 | 8 | テスト社員8 |
| 9 | 9 | テスト社員9 |
| 10 | 10 | テスト社員10 |
何階層も副問い合わせを実行すると、処理が複雑になってしまいます。ROWNUMではなくROW_NUMBER()を使えば副問い合わせをせずに、ソートしたあとの行番号を取得することができます。
SELECT
T1.行番号
,T1.社員コード
,T1.社員名
FROM (
SELECT
ROW_NUMBER() OVER(ORDER BY T1.社員コード) 行番号
,T1.社員コード
,T1.社員名
FROM
社員マスタ T1
) T1
WHERE
T1.行番号 BETWEEN 6 AND 10
ORDER BY T1.行番号集計関数(SUM,COUNT,MAXなど)にOVER(...)つけて、分析関数として、効率よくデータを集計することができます。
SQL OVER句の分析関数で効率よくデータを集計するで分析関数の基本的な使い方を紹介します。