ORA-01003: no statement parsed は、Oracleでカーソルを使った処理を実行・フェッチ・バインドしようとした時に、そのカーソルへパース済みのSQL文が関連付いていない場合に発生するエラーです。特に DBMS_SQL、OCI系のアプリ、古いForms/Reports、動的SQLをラップした処理で見かけます。
Oracle公式の説明では、ホスト言語プログラムの呼び出しが、関連付けられたパース済みSQL文を持たないカーソルを参照したことが原因です。対処は、データをフェッチする前にSQL文をパースして実行することです。
ORA-01003が出たら、カーソルに対して
PARSE が成功しているか、その後に EXECUTE や FETCH しているかを確認します。空SQL、パース失敗後の続行、クローズ済みカーソルの再利用、別カーソル変数の取り違えが定番原因です。ORA-01003とは
Oracleでカーソルを低レベルに扱う処理では、一般に「カーソルを開く」「SQLをパースする」「バインドする」「実行する」「フェッチする」という順番があります。ORA-01003は、このうちSQLをパースしてカーソルへ関連付ける段階が抜けている、または失敗している時に起きます。
| 確認点 | よくある原因 | 見る場所 |
|---|---|---|
| パース済みか | DBMS_SQL.PARSE が呼ばれていない |
DBMS_SQLの呼び出し順 |
| パース成功後か | 例外を握りつぶして後続処理を続けている | 例外処理、ログ |
| SQL文字列 | 空文字、NULL、不完全なSQLを渡している | 実行直前のSQLログ |
| カーソル状態 | クローズ後や別カーソルを操作している | OPEN/CLOSEの位置 |
| アプリ側 | prepare前にexecute/fetch相当の処理をしている | JDBC/OCI/ラッパー |
DBMS_SQL の基本は DBMS_SQL完全ガイド、単純な動的SQLは EXECUTE IMMEDIATEガイド も参考になります。
ORA-01001・ORA-01002との違い
ORA-01003はカーソル系のエラーですが、似たものに ORA-01001 と ORA-01002 があります。切り分けでは、カーソルが無効なのか、フェッチ順が不正なのか、そもそもSQLがパースされていないのかを分けます。
ORA-01003
主な意味: カーソルにパース済みSQL文が関連付いていない
見る場所: PARSE、EXECUTE、FETCHの順番
ORA-01001
主な意味: 無効なカーソルを操作している
関連記事: ORA-01001
ORA-01002
主な意味: フェッチ順やカーソル状態が不正
関連記事: ORA-01002
DBMS_SQL.PARSE前にEXECUTEしている
DBMS_SQL では、開いたカーソルにSQL文を PARSE してから EXECUTE します。カーソルを開いただけで実行すると、カーソルにSQLが関連付いていないためORA-01003の原因になります。
DECLARE c INTEGER; n INTEGER; BEGIN c := DBMS_SQL.OPEN_CURSOR; -- NG: PARSEしていないカーソルを実行している n := DBMS_SQL.EXECUTE(c); DBMS_SQL.CLOSE_CURSOR(c); END; /
DECLARE
c INTEGER;
n INTEGER;
BEGIN
c := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(
c,
'UPDATE employees SET updated_at = SYSDATE WHERE employee_id = :id',
DBMS_SQL.NATIVE
);
DBMS_SQL.BIND_VARIABLE(c, ':id', 100);
n := DBMS_SQL.EXECUTE(c);
DBMS_SQL.CLOSE_CURSOR(c);
END;
/
SELECTをPARSEしただけでFETCHしている
SELECT文では、PARSE だけでなく EXECUTE、必要に応じて DEFINE_COLUMN、FETCH_ROWS、COLUMN_VALUE の順番も確認します。処理順が崩れると、ORA-01003や周辺のカーソルエラーにつながります。
DECLARE
c INTEGER;
n INTEGER;
v_name VARCHAR2(100);
BEGIN
c := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(c,
'SELECT employee_name FROM employees WHERE employee_id = :id',
DBMS_SQL.NATIVE);
DBMS_SQL.BIND_VARIABLE(c, ':id', 100);
DBMS_SQL.DEFINE_COLUMN(c, 1, v_name, 100);
n := DBMS_SQL.EXECUTE(c);
IF DBMS_SQL.FETCH_ROWS(c) > 0 THEN
DBMS_SQL.COLUMN_VALUE(c, 1, v_name);
END IF;
DBMS_SQL.CLOSE_CURSOR(c);
END;
/
パース失敗後に処理を続けている
SQL文の構文エラー、存在しない表や列、権限不足などで PARSE が失敗したのに、例外を握りつぶして EXECUTE や FETCH を続けると、後続でORA-01003として見えることがあります。本当の原因はORA-009xxや権限エラーの方にある場合があります。
DECLARE
c INTEGER;
n INTEGER;
BEGIN
c := DBMS_SQL.OPEN_CURSOR;
BEGIN
-- NG: SQLが不完全でPARSEに失敗する
DBMS_SQL.PARSE(c, 'SELECT FROM employees', DBMS_SQL.NATIVE);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
-- ここで続行すると原因が分かりにくくなる
END;
n := DBMS_SQL.EXECUTE(c);
DBMS_SQL.CLOSE_CURSOR(c);
END;
/
PARSE が失敗したら、そのSQL文字列、エラー番号、バインド一覧をログに出して処理を止めます。SQL構文の切り分けでは ORA-00911、バインド不足なら ORA-01008、SQLにないバインドを渡しているなら ORA-01006 も確認します。
動的SQLの調査では、DBMS_SQL.LAST_ERROR_POSITION でパースエラー位置を残すと原因箇所を追いやすくなります。エラースタックに ORA-06512 が出ている場合は、ORA-06512の読み方 で呼び出し元の行番号も確認します。
DECLARE
c INTEGER;
v_sql VARCHAR2(4000) := 'SELECT FROM employees';
BEGIN
c := DBMS_SQL.OPEN_CURSOR;
BEGIN
DBMS_SQL.PARSE(c, v_sql, DBMS_SQL.NATIVE);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQL=' || v_sql);
DBMS_OUTPUT.PUT_LINE('ERR=' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('POS=' || DBMS_SQL.LAST_ERROR_POSITION);
IF DBMS_SQL.IS_OPEN(c) THEN
DBMS_SQL.CLOSE_CURSOR(c);
END IF;
RAISE;
END;
DBMS_SQL.CLOSE_CURSOR(c);
END;
/
SQL文字列がNULLまたは空になっている
動的SQLを条件分岐で作っていると、実行直前のSQL文字列が NULL や空文字、不完全な文になっていることがあります。ソース上では代入しているつもりでも、分岐に入らず空のままになるケースです。
DECLARE
v_sql VARCHAR2(4000);
BEGIN
-- 条件によってv_sqlに何も入らないことがある
IF v_sql IS NULL OR TRIM(v_sql) IS NULL THEN
RAISE_APPLICATION_ERROR(-20001, 'SQL text is empty');
END IF;
EXECUTE IMMEDIATE v_sql;
END;
/
エラー時には、SQL文字列そのものをログへ出します。バインド値だけをログに出しても、カーソルへどのSQLをパースしたのか分からないため、原因を追いにくくなります。
カーソルの取り違え・クローズ後操作
複数のカーソル変数を扱う処理では、パースしたカーソルと実行するカーソルが違っていないか確認します。また、クローズ済みカーソルを再利用すると、ORA-01001 など別のカーソルエラーとして出ることもあります。
DECLARE c_parsed INTEGER; c_exec INTEGER; n INTEGER; BEGIN c_parsed := DBMS_SQL.OPEN_CURSOR; c_exec := DBMS_SQL.OPEN_CURSOR; DBMS_SQL.PARSE(c_parsed, 'DELETE FROM work_table', DBMS_SQL.NATIVE); -- NG: PARSEしたc_parsedではなく、別カーソルc_execを実行している n := DBMS_SQL.EXECUTE(c_exec); DBMS_SQL.CLOSE_CURSOR(c_exec); DBMS_SQL.CLOSE_CURSOR(c_parsed); END; /
JDBCやアプリ側で起きる場合
JDBCなど通常の高レベルAPIでは、明示的にPARSEを呼ぶことは少ないです。それでも、内部でStatementを再利用しているラッパー、SQLが空のまま渡される処理、prepare失敗後のexecute継続で似た状況になります。
String sql = buildSql(request);
if (sql == null || sql.isBlank()) {
throw new IllegalArgumentException("SQL text is empty");
}
try (PreparedStatement ps = conn.prepareStatement(sql)) {
bindParameters(ps, request);
ps.executeQuery();
}
アプリでは、prepare/parseに相当する処理で失敗した例外を握りつぶさないことが大切です。列数の取り違えなら ORA-01007、バインド名や番号なら ORA-01036 も確認します。
調査手順
ORA-01003は、最初に失敗した場所が別にあることも多いです。後続のORA-01003だけを見るのではなく、直前のパースエラーやSQLログを確認します。
| 順番 | 確認すること | 見るポイント |
|---|---|---|
| 1 | 実行直前のSQL文字列を確認する | NULL、空、不完全なSQLではないか |
| 2 | PARSEが成功しているか確認する | 例外を握りつぶしていないか |
| 3 | PARSEしたカーソルを実行しているか確認する | 別カーソル変数を使っていないか |
| 4 | EXECUTE/FETCHの順番を見る | PARSE、BIND、DEFINE、EXECUTE、FETCHの順番 |
| 5 | 周辺エラーと分ける | ORA-01001、ORA-01002、ORA-01006、ORA-01036 |
チェックリスト
DBMS_SQL.PARSEをEXECUTEより前に呼んでいるPARSEで例外が出たら後続処理を止めている- パース失敗時に
DBMS_SQL.LAST_ERROR_POSITIONとSQL文字列をログに残している - 例外時も
DBMS_SQL.IS_OPENを確認してカーソルを閉じている - 実行直前のSQL文字列がNULLや空ではない
- パースしたカーソルと実行するカーソルが同じ
- SELECTでは
DEFINE_COLUMN、EXECUTE、FETCH_ROWSの順番を確認した - クローズ済みカーソルを再利用していない
- アプリ側でprepare失敗後にexecuteを続けていない
よくある質問
ORA-01003はSQL構文エラーですか?
直接の意味は、カーソルにパース済みSQLが関連付いていないことです。ただし、その前段でSQL構文エラーが起きて PARSE に失敗しているケースはあります。
EXECUTE IMMEDIATEでもORA-01003になりますか?
通常の EXECUTE IMMEDIATE では低レベルのPARSE順序を意識しません。ただしSQL文字列が空、不完全、例外処理で失敗を隠している場合は、周辺エラーとして確認が必要です。
ORA-01001との違いは何ですか?
ORA-01001は無効なカーソルを操作している問題です。ORA-01003は、カーソル自体は参照しているものの、そこにパース済みSQLが関連付いていない問題として切り分けます。
まとめ
ORA-01003は、カーソルにパース済みSQL文が関連付いていない時に発生します。DBMS_SQL.PARSE が成功しているか、パースしたカーソルを実行しているか、SQL文字列が空でないかを確認しましょう。
後続でORA-01003が出ていても、本当の原因は直前のパース失敗にあることがあります。SQL文字列、バインド値、例外ログ、カーソルのOPEN/CLOSEをセットで確認するのが近道です。
参考
ORA-01003 – Oracle Database Error Help
DBMS_SQL – Oracle Database PL/SQL Packages and Types Reference
PL/SQL Dynamic SQL – Oracle Database PL/SQL Language Reference

