OracleでもLIMITのように件数を指定したい

MySQLPostgreSQLでは、出力する件数を指定する LIMIT 句が用意されているが、Oracle Databaseには存在しないため他の記法を利用する必要がある。毎回忘れるので備忘のため記事にしておく。

サンプルデータ

SQLで操作するためのサンプルデータとして、以下のような id に都道府県コード、name に都道府県名のローマ字表記にしたものをレコードに持つテーブルを作成する。

id name
1 Hokkaido
2 Aomori
... ...
46 Kagoshima
47 Okinawa

ただし、あとでソートの操作との組み合わせを確認する際に分かりやすくするため、id の連番ではなく適当に並べ替えた順番で INSERT していく。

CREATE TABLE prefecture (
    id NUMBER,
    name VARCHAR2(10)
);

INSERT INTO prefecture VALUES (1, 'Hokkaido');
INSERT INTO prefecture VALUES (24, 'Mie');
INSERT INTO prefecture VALUES (10, 'Gunma');
INSERT INTO prefecture VALUES (2, 'Aomori');
INSERT INTO prefecture VALUES (17, 'Ishikawa');

(中略)

INSERT INTO prefecture VALUES (7, 'Fukushima');
INSERT INTO prefecture VALUES (42, 'Nagasaki');
INSERT INTO prefecture VALUES (34, 'Hiroshima');
INSERT INTO prefecture VALUES (44, 'Oita');
INSERT INTO prefecture VALUES (47, 'Okinawa');

作成した直後に全件 select をかけると、以下のように INSERT した順番で出力される。

SQL> SELECT * FROM prefecture;

    ID NAME
---------- ----------
     1 Hokkaido
    24 Mie
    10 Gunma
     2 Aomori
    17 Ishikawa

(中略)

    ID NAME
---------- ----------
    34 Hiroshima
    44 Oita
    47 Okinawa

47 rows selected.

(参考)limit 句を使おうとすると、正常な SQL とみなされずエラーになる。

SQL> SELECT * FROM prefecture LIMIT 10;
SELECT * FROM prefecture LIMIT 10
                               *
ERROR at line 1:
ORA-00933: SQL command not properly ended

ROWNUM を使う

WHERE句の中で ROWNUM を使って、取得する行数を指定する。例えば、先頭の10行を取得したい場合は WHERE ROWNUM <= 10 のように指定する。

SQL> SELECT * FROM prefecture WHERE ROWNUM <= 10;

    ID NAME
---------- ----------
     1 Hokkaido
    24 Mie
    10 Gunma
     2 Aomori
    17 Ishikawa
    39 Kochi
     6 Yamagata
    41 Saga
    11 Saitama
     8 Ibaraki

10 rows selected.

ソートした上で行数を指定したい場合は注意が必要。SQL では WHERE > ORDER の順に記述する必要があるので、愚直に書くと取得したものをソートしたものが出力されることになる。

SQL> SELECT * FROM prefecture WHERE ROWNUM <= 10 ORDER BY id;

    ID NAME
---------- ----------
     1 Hokkaido
     2 Aomori
     6 Yamagata
     8 Ibaraki
    10 Gunma
    11 Saitama
    17 Ishikawa
    24 Mie
    39 Kochi
    41 Saga

10 rows selected.

SQL> SELECT * FROM prefecture ORDER BY id WHERE ROWNUM <= 10;
SELECT * FROM prefecture ORDER BY id WHERE ROWNUM <= 10
                                     *
ERROR at line 1:
ORA-00933: SQL command not properly ended

ソートしたものの先頭行を取得したい場合には、副問合せの形で書く必要がある。

SQL> SELECT * FROM (SELECT * FROM prefecture ORDER BY id) WHERE ROWNUM <= 10;

    ID NAME
---------- ----------
     1 Hokkaido
     2 Aomori
     3 Iwate
     4 Miyagi
     5 Akita
     6 Yamagata
     7 Fukushima
     8 Ibaraki
     9 Tochigi
    10 Gunma

10 rows selected.

FETCH FIRST N ROWS ONLY を使う

Oracle Database 12c 以降で追加されている構文。該当するものの先頭 N 行を取得する。

SQL> SELECT * FROM prefecture FETCH FIRST 10 ROWS ONLY;

    ID NAME
---------- ----------
     1 Hokkaido
    24 Mie
    10 Gunma
     2 Aomori
    17 Ishikawa
    39 Kochi
     6 Yamagata
    41 Saga
    11 Saitama
     8 Ibaraki

10 rows selected.

ROWNUM の際と同様に、ORDER と組み合わせたい場合は注意が必要。こちらの場合は ORDER > FETCH の順に記載する必要がある。

SQL> SELECT * FROM prefecture FETCH FIRST 10 ROWS ONLY ORDER BY id;
SELECT * FROM prefecture FETCH FIRST 10 ROWS ONLY ORDER BY id
                                                  *
ERROR at line 1:
ORA-00933: SQL command not properly ended

SQL> SELECT * FROM prefecture ORDER BY id FETCH FIRST 10 ROWS ONLY;

    ID NAME
---------- ----------
     1 Hokkaido
     2 Aomori
     3 Iwate
     4 Miyagi
     5 Akita
     6 Yamagata
     7 Fukushima
     8 Ibaraki
     9 Tochigi
    10 Gunma

10 rows selected.

指定した行数を取得してからソートしたい場合は、副問合せの形で書く必要がある。

SQL> SELECT * FROM (SELECT * FROM prefecture FETCH FIRST 10 ROWS ONLY) ORDER BY id;

    ID NAME
---------- ----------
     1 Hokkaido
     2 Aomori
     6 Yamagata
     8 Ibaraki
    10 Gunma
    11 Saitama
    17 Ishikawa
    24 Mie
    39 Kochi
    41 Saga

10 rows selected.

こちらの記法の方が limit 句と同じように記述できるため、MySQLPostgreSQL をすでに利用しているのであれば理解しやすいと思う。

Oracle Database 12c 以前では使えないというデメリットはあるが、12c がリリースされたのは 2014年であるため、比較的新しいサービスであれば問題なく利用できるのではないかと思う。

参考サイト