ORA-00911: invalid character は、SQL文の中にOracleが認識できない文字が含まれているときに発生するエラーです。日本語環境では「無効な文字です」と表示されます。
よくある原因は、アプリから実行するSQLの末尾に付けたセミコロン、全角スペース、全角記号、識別子に使えない特殊文字、引用符の崩れ、動的SQLの文字列連結ミスです。SQL Developerでは動くのにJDBCやPython、PHPから実行すると落ちる場合もあります。
ORA-00911は、エラー位置の直前にある文字、またはSQLに紛れた見えにくい文字を取り除くと解消できます。アプリ実行ではSQL終端の
; やSQL*Plusの / を送らない、全角スペースを半角に直す、識別子に特殊文字を使わない、必要なら識別子をダブルクォートで囲む、という順に確認します。ORA-00911とは
Oracle公式のエラー説明では、ORA-00911はSQL文内で無効な文字が見つかった場合に発生し、その文字を削除するか、識別子の一部ならダブルクォートで囲むことが対処として案内されています。新しいエラーメッセージでは、どの文字がどのトークンの後で無効だったかが示されることもあります。識別子に通常使える特殊文字は $、#、_ ですが、先頭には使えません。
| 原因 | よくある例 | 修正の方向 |
|---|---|---|
| アプリ実行時のセミコロン | SELECT ...; をJDBCなどへ渡す |
SQL文字列の末尾の ; を外す |
| SQL*Plusのスラッシュ | / をアプリのSQL文字列へ含める |
SQLツールの実行記号とSQL本文を分ける |
| 全角スペース・不可視文字 | コピーしたSQLに見えない文字が混ざる | SQLを整形し、全角文字を半角へ直す |
| 識別子の特殊文字 | user~id のような列名 |
名前を直すか、必要ならダブルクォートで囲む |
| 引用符の崩れ | 全角引用符や閉じ忘れ | 文字列はシングルクォート、識別子はダブルクォートに分ける |
| 動的SQLの連結ミス | 変数値や識別子がそのままSQLへ混ざる | 完成SQLをログに出して確認する |
まずエラー位置の直前を見る
ORA-00911では、エラー位置として表示された場所そのものより、直前のトークンや文字を見ると原因に近づきやすいです。SQLを1行で見ず、SELECT句、FROM句、WHERE句、ORDER BY句ごとに改行して確認します。
-- まず整形して、怪しい文字を見つけやすくする
SELECT employee_id,
employee_name
FROM employees
WHERE status = 'ACTIVE'
ORDER BY employee_id;
アプリから実行するSQL末尾のセミコロン
もっとも多い原因の1つが、JDBC、Python、PHPなどのアプリから実行するSQL文字列に、SQL Developer用のセミコロンを含めているケースです。SQL DeveloperやSQL*Plusでは ; が文の区切りとして使われますが、アプリから1文として送るSQLには不要です。
-- NG: アプリから実行するSQL文字列にセミコロンを含めている SELECT * FROM employees WHERE employee_id = :employee_id; -- OK: アプリへ渡すSQL文字列では末尾のセミコロンを外す SELECT * FROM employees WHERE employee_id = :employee_id
SQL Developer上で直接実行するSQLと、アプリの execute に渡すSQL文字列は分けて考えます。バインド変数の渡し方は ORA-01008の原因と解決方法 も参考になります。
SQL*Plusのスラッシュをアプリへ渡しているケース
SQL*PlusやSQLclでは、PL/SQLブロックを実行するために次の行へ / を書くことがあります。しかし、この / はSQL本文ではなくツール側の実行指示です。JDBC、Python、PHP、EXECUTE IMMEDIATE などへそのまま含めると、無効な文字として扱われることがあります。
-- SQL*Plus / SQLclで手動実行するときは / でブロックを実行する
BEGIN
UPDATE employees
SET status = 'ACTIVE'
WHERE employee_id = 100;
END;
/
-- アプリや動的SQLへ渡す文字列には、実行用の / を含めない
BEGIN
UPDATE employees
SET status = 'ACTIVE'
WHERE employee_id = 100;
END;
EXECUTE IMMEDIATE内のセミコロン
PL/SQLの EXECUTE IMMEDIATE でも、動的SQL文字列の中に通常SQLの末尾セミコロンを入れるとORA-00911の原因になります。PL/SQLブロック全体を動的実行する場合と、単体のSQL文を動的実行する場合を分けて確認します。
-- NG: 動的SQL文字列の末尾にセミコロンを入れている
BEGIN
EXECUTE IMMEDIATE 'UPDATE employees SET status = ''ACTIVE'' WHERE employee_id = 100;';
END;
/
-- OK: 通常のSQL文として渡すならセミコロンを含めない
BEGIN
EXECUTE IMMEDIATE 'UPDATE employees SET status = ''ACTIVE'' WHERE employee_id = 100';
END;
/
動的SQLの書き方は EXECUTE IMMEDIATE完全ガイド でも詳しく整理しています。
全角スペースや全角記号が混ざっているケース
Webページ、Excel、チャット、ドキュメントからSQLをコピーすると、全角スペースや見えにくい記号が混ざることがあります。見た目では半角スペースに見えても、Oracleからは別の文字として扱われるためORA-00911になることがあります。
-- NG例: SELECTと列名の間、列名の前後に全角スペースが混ざっていることがある -- SELECT employee_id FROM employees; -- OK: 全角スペースを半角スペースへ直す SELECT employee_id FROM employees;
原因が見えない場合は、SQLをテキストエディタに貼り付けて不可視文字を表示する、または一度プレーンテキスト化してから打ち直します。
識別子に使えない特殊文字が入っているケース
Oracleの通常の識別子では、英数字と一部の記号を使えますが、~、-、空白などはそのままでは使えません。列名や別名、テーブル名に特殊文字を含めたい場合は、ダブルクォートで囲んだ引用符付き識別子になります。
-- NG: user~id は通常の識別子として無効 SELECT user~id FROM users; -- OK: そのような列名が実在するならダブルクォートで囲む SELECT "user~id" FROM users; -- 推奨: 可能なら通常の識別子へ直す SELECT user_id FROM users;
引用符付き識別子は大文字小文字も区別され、後続のSQLでも毎回ダブルクォートが必要になります。新規設計なら、特殊文字を含まない列名へ寄せるほうが運用しやすいです。
別名にハイフンや記号を使っているケース
列別名にハイフンやスラッシュを使うと、Oracleは演算子や無効な文字として解釈することがあります。表示用の別名に記号を含めたい場合はダブルクォートで囲みます。
-- NG: employee-name は通常の別名として無効 SELECT employee_name AS employee-name FROM employees; -- OK: 表示用の別名ならダブルクォートで囲む SELECT employee_name AS "employee-name" FROM employees; -- 推奨: SQL内で扱いやすい別名にする SELECT employee_name AS employee_name FROM employees;
文字列リテラルの引用符が崩れているケース
文字列はシングルクォートで囲みます。全角の引用符、バッククォート、スマートクォートが混ざると、Oracleが文字列として認識できずORA-00911や別の構文エラーになります。
-- NG: バッククォートや全角引用符を使わない -- SELECT * FROM employees WHERE status = `ACTIVE`; -- SELECT * FROM employees WHERE status = ’ACTIVE’; -- OK: 文字列はシングルクォートで囲む SELECT * FROM employees WHERE status = 'ACTIVE';
q引用符の区切り文字が不正なケース
Oracleの代替引用符 q'[...]' は、文字列内にシングルクォートを含めたいときに便利です。ただし、区切り文字にスペース、タブ、改行などを使うとORA-00911の原因になります。
-- OK: [] を区切りに使う
SELECT q'[It's active]'
FROM dual;
-- OK: {} や <> など分かりやすい区切りを使う
SELECT q'{status = 'ACTIVE'}'
FROM dual;
CREATE USERやパスワードで特殊文字を使うケース
CREATE USER や ALTER USER のパスワードに特殊文字を含める場合、文字によってはそのまま書くと無効な文字として解釈されることがあります。Oracle公式の説明でも、パスワードを指定する場合はダブルクォートで囲むことが推奨されています。
-- 特殊文字を含むパスワードはダブルクォートで囲む CREATE USER app_user IDENTIFIED BY "Str0ng#Pass!2026"; ALTER USER app_user IDENTIFIED BY "Next#Pass!2026";
動的SQLでオブジェクト名を連結しているケース
動的SQLでスキーマ名、テーブル名、列名を文字列連結する場合、値に特殊文字や余分なセミコロンが混ざるとORA-00911になります。値はバインド変数にし、オブジェクト名は許可リストで検証してからSQLへ組み込みます。
-- NGの考え方: 入力値をそのままSQLへ連結する -- v_sql := 'SELECT * FROM ' || v_table_name || ' WHERE employee_id = :id'; -- OKの考え方: テーブル名は許可リストで確認し、値はバインドする v_sql := 'SELECT * FROM employees WHERE employee_id = :id'; EXECUTE IMMEDIATE v_sql INTO v_row USING v_employee_id;
動的SQLとバインド変数の分け方は Oracleのバインド変数完全ガイド も参考になります。
ORA-00933・ORA-00936・ORA-00907との違い
ORA-00911 は無効な文字が中心です。似た構文エラーとして、句の終わり方が原因の ORA-00933、式不足の ORA-00936、括弧不足の ORA-00907 があります。
| エラー | 主な原因 | 見る場所 |
|---|---|---|
ORA-00911 |
無効な文字、セミコロン、全角文字、特殊文字 | エラー位置の直前、SQL末尾、識別子 |
ORA-00933 |
句の順序、SQLの終わり方、他DB構文 | LIMIT、UPDATE JOIN、余分な句 |
ORA-00936 |
式、列、値、条件の不足 | SELECT 句、WHERE 句、関数引数 |
ORA-00907 |
右括弧不足、括弧内の構文ミス | 関数、IN句、CHECK制約、サブクエリ |
句の終わり方が怪しい場合は ORA-00933の原因と解決方法、式不足なら ORA-00936の原因と解決方法、括弧が怪しい場合は ORA-00907の原因と解決方法 を確認してください。
修正チェックリスト
| 手順 | 確認すること | 見るポイント |
|---|---|---|
| 1 | SQL末尾を見る | アプリ実行SQLに ; を含めていないか |
| 2 | SQL*Plusの実行記号を見る | / をアプリや動的SQLへ渡していないか |
| 3 | 全角文字を確認する | 全角スペース、全角記号、スマートクォートがないか |
| 4 | 識別子を見る | 列名、別名、テーブル名に特殊文字がないか |
| 5 | 引用符を見る | 文字列はシングルクォート、識別子はダブルクォートに分けているか |
| 6 | 動的SQLを見る | 連結した完成SQLをログに出しているか |
| 7 | アプリとSQLツールを分ける | SQL Developer用の書き方をアプリへそのまま渡していないか |
| 8 | 似た構文エラーと切り分ける | ORA-00933、ORA-00936、ORA-00907ではないか |
よくある質問
SQL Developerでは動くのにアプリからORA-00911になるのはなぜですか?
SQL Developerでは末尾のセミコロンが文の区切りとして扱われますが、アプリのexecuteに渡すSQL文字列では不要な文字になることがあります。アプリへ渡すSQLから ; を外して確認します。
SQL*Plusのスラッシュも外す必要がありますか?
アプリや動的SQLへ渡す場合は外します。/ はSQL*PlusやSQLclでPL/SQLブロックを実行するためのツール側の記号で、SQL本文として送る文字ではありません。
全角スペースでもORA-00911になりますか?
なることがあります。コピーしたSQLに全角スペースや不可視文字が混ざっていると、見た目では分かりにくいので、不可視文字を表示できるエディタで確認します。
特殊文字を含む列名は使えますか?
ダブルクォートで囲めば使える場合がありますが、大文字小文字の区別や毎回クォートが必要になるため、新規設計では通常の識別子にするのがおすすめです。
ORA-00911とORA-00933の違いは?
ORA-00911は無効な文字そのものが原因です。ORA-00933は句の順序やSQLの終わり方、Oracleで使えない構文が原因になりやすいです。
まとめ
ORA-00911は、SQLにOracleが認識できない文字が含まれると発生します。まずSQL末尾のセミコロン、全角スペース、全角記号、識別子の特殊文字、引用符を確認しましょう。
SQL DeveloperやSQL*Plusで実行するSQLと、アプリから送るSQL文字列では、扱いが違うことがあります。アプリ実行時は末尾の ; を外し、動的SQLでは完成したSQLをログに出して、無効な文字が混ざっていないか確認します。
参考
ORA-00911 – Oracle Database Error Help
Database Object Names and Qualifiers – Oracle SQL Language Reference

