【Oracle】ORA-00904: 無効な識別子です の原因と解決方法完全ガイド|列名ミス・エイリアス・引用符・予約語まで解説

【Oracle】ORA-00904: 無効な識別子です の原因と解決方法完全ガイド|列名ミス・エイリアス・引用符・予約語まで解説 Oracle

ORA-00904: 無効な識別子です(英語: invalid identifier)は、Oracle開発の現場で日常的に遭遇するエラーです。列名・テーブル名・エイリアスなどの識別子が無効だとOracleが判断したときに発生します。エラーメッセージ自体はシンプルですが、発生パターンは多岐にわたり、特に引用符付き識別子の挙動はベテランでもはまりやすいポイントです。本記事では代表的な発生パターンごとに原因と対処法を体系的に解説します。

この記事でわかること

  • ORA-00904 の発生メカニズムと識別子のルール
  • 列名スペルミス・大文字小文字が原因のパターン
  • 引用符付き識別子(ダブルクォート)が原因のパターン
  • SELECT 列エイリアスを WHERE・GROUP BY・HAVING で使うとエラーになる理由
  • テーブルエイリアスの誤用が原因のパターン
  • 予約語を列名に使うときの注意点
  • INSERT・UPDATE 文での列名ミス
  • USER_TAB_COLUMNS・DESCRIBE を使った列名確認方法
スポンサーリンク

ORA-00904 の発生メカニズム

Oracleの識別子とは、列名・テーブル名・ビュー名・エイリアスなどSQL内で参照する名前のことです。Oracleが識別子を認識できないときに ORA-00904 が発生します。

識別子には引用符なし(通常識別子)引用符あり(引用符付き識別子)の2種類があり、挙動が大きく異なります。

種類 記述例 大文字小文字 使用可能文字
通常識別子 EMPLOYEE_ID 大文字に自動変換 英数字・_・$・#(先頭は英字)
引用符付き識別子 “employee_id” そのまま保持(区別あり) ほぼすべての文字(スペース・予約語も可)

通常識別子はOracleが内部で大文字に変換して管理します。一方、ダブルクォートで囲んだ引用符付き識別子は大文字小文字を区別して保持します。この違いが ORA-00904 の最大の落とし穴になります。

パターン:列名のスペルミス・存在しない列

最も基本的なパターンです。単純なスペルミスや、そもそも存在しない列名を参照すると発生します。

ORA-00904 の基本例(列名ミス)
-- employees テーブルに employee_name 列は存在しない(正しくは last_name)
SELECT employee_name FROM employees;
-- → ORA-00904: "EMPLOYEE_NAME": 無効な識別子です

エラーメッセージに含まれる識別子名をもとに、実際の列名を確認します。

列名確認:USER_TAB_COLUMNS で列一覧を表示
-- テーブルの列名・データ型・桁数を確認する
SELECT column_name, data_type, data_length, nullable
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'   -- テーブル名は大文字で指定
ORDER BY column_id;
列名確認:DESCRIBE コマンド(SQL*Plus / SQL Developer)
DESC employees;
-- または
DESCRIBE employees;

ポイント:USER_TAB_COLUMNStable_name は大文字で格納されているため、WHERE条件は大文字で指定します。スキーマをまたいで参照する場合は ALL_TAB_COLUMNS または DBA_TAB_COLUMNS を使います。

パターン:引用符付き識別子の大文字小文字不一致

テーブルや列をダブルクォートで囲んで作成した場合、参照時も同じ大文字小文字で囲む必要があります。これを忘れると ORA-00904 が発生します。

NG: 引用符付き識別子を通常識別子として参照
-- 列が "employee_id"(小文字)で作成されている場合
CREATE TABLE test_table (
    "employee_id" NUMBER,   -- 小文字で作成
    name          VARCHAR2(100)
);

-- 通常識別子で参照すると大文字に変換される → EMPLOYEE_ID を探すがない
SELECT employee_id FROM test_table;
-- → ORA-00904: "EMPLOYEE_ID": 無効な識別子です

-- ダブルクォートなしで引用符付き列名と同じ綴りを書いても大文字変換で不一致
SELECT Employee_Id FROM test_table;
-- → ORA-00904: "EMPLOYEE_ID": 無効な識別子です
OK: 引用符付き識別子は作成時と同じ大文字小文字で参照
-- "employee_id"(小文字)で作成した列は、参照時も同じ書き方が必要
SELECT "employee_id" FROM test_table;

-- 通常識別子(大文字変換)で作成した列は引用符不要
SELECT name FROM test_table;   -- NAME と同じ意味
引用符付き識別子の落とし穴
外部ツール(ETLツール・ORMフレームワーク等)が自動生成したDDLにダブルクォートが含まれていることがあります。そのような列を手書きのSQLで参照する際は、必ずダブルクォートと正確な大文字小文字を使ってください。
ベストプラクティス:引用符付き識別子は使わない
新規テーブル設計では、ダブルクォートなしで作成できる通常識別子(大文字・アンダースコア)を使うことを強く推奨します。引用符付き識別子は保守性が下がり、ORA-00904 の温床になります。

パターン:SELECT のエイリアスを WHERE・GROUP BY で参照

SELECT 句で付けた列エイリアスを WHERE 句や GROUP BY 句で直接参照するとORA-00904が発生します。これはSQLの評価順序に起因するOracleの仕様です。

NG: SELECT エイリアスを WHERE 句で参照
-- total_price という名前は SELECT の評価後に決まるが、
-- WHERE 句は SELECT より先に評価される
SELECT product_id,
       quantity * unit_price AS total_price
FROM order_items
WHERE total_price >= 10000;
-- → ORA-00904: "TOTAL_PRICE": 無効な識別子です
OK: サブクエリで包んでエイリアスを外部クエリで参照
-- サブクエリの SELECT が先に実行されて total_price が確定する
SELECT *
FROM (
    SELECT product_id,
           quantity * unit_price AS total_price
    FROM order_items
)
WHERE total_price >= 10000;
OK: WHERE 句に元の式を直接書く
-- エイリアスを使わずに同じ計算式を WHERE 句に書く
SELECT product_id,
       quantity * unit_price AS total_price
FROM order_items
WHERE quantity * unit_price >= 10000;

GROUP BY でのエイリアス参照も同様です。ただし ORDER BY 句はエイリアスを使えます(ORDER BY は SELECT の後に評価されるため)。

SQLの評価順序とエイリアスの有効範囲
-- 評価順序(概念):
--   FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
--
-- SELECT エイリアスが有効なのは ORDER BY のみ
-- WHERE / GROUP BY / HAVING では使用不可

-- OK: ORDER BY ではエイリアスが使える
SELECT product_id,
       quantity * unit_price AS total_price
FROM order_items
ORDER BY total_price DESC;   -- ← エイリアス使用可

-- NG: GROUP BY ではエイリアスが使えない
SELECT department_id,
       SUM(salary) AS total_salary
FROM employees
GROUP BY total_salary;   -- → ORA-00904: "TOTAL_SALARY": 無効な識別子です

-- OK: GROUP BY には元の列または式を書く
SELECT department_id,
       SUM(salary) AS total_salary
FROM employees
GROUP BY department_id;

パターン:テーブルエイリアスの誤用

テーブルに付けたエイリアスを間違えると ORA-00904 が発生します。特にサブクエリや複数テーブルJOINで起きやすいパターンです。

NG: 存在しないテーブルエイリアスを使用
-- エイリアス e を定義しているのに、別の箇所で emp と書いてしまっている
SELECT e.employee_id, emp.last_name
FROM employees e
WHERE e.department_id = 10;
-- → ORA-00904: "EMP"."LAST_NAME": 無効な識別子です
NG: エイリアスを定義したのに元のテーブル名で参照
-- FROM に e と書いたのに SELECT でテーブル名を使おうとしている
SELECT employees.last_name, e.salary
FROM employees e
WHERE e.department_id = 10;
-- → ORA-00904: "EMPLOYEES"."LAST_NAME": 無効な識別子です
-- エイリアス e を定義した時点でテーブル名 employees は使えなくなる
OK: 定義したエイリアスで統一して参照
-- エイリアス e を定義して一貫して使う
SELECT e.employee_id, e.last_name, e.salary
FROM employees e
WHERE e.department_id = 10;
エイリアス定義のスコープ
FROM 句でエイリアスを定義すると、そのSQL内では元のテーブル名での参照ができなくなります。一度エイリアスを付けたら、そのSQL全体でエイリアスで統一して参照してください。

パターン:予約語を列名・エイリアスとして使う

OracleのSQL予約語(SELECT・FROM・WHERE・DATE・LEVEL・NUMBER など)を列名やエイリアスとして使おうとすると ORA-00904 が発生することがあります。

NG: 予約語 DATE をエイリアスに使う
-- DATE は予約語
SELECT sysdate AS date FROM dual;
-- → ORA-00904 または ORA-00923(文脈による)
OK: ダブルクォートで囲めば予約語でも識別子として使える
-- ダブルクォートで囲むと予約語をエイリアスに使える
SELECT sysdate AS "date" FROM dual;

-- ただし参照時も引用符が必要なため、なるべく予約語以外の名前を選ぶのが無難
-- 推奨: わかりやすい別名にする
SELECT sysdate AS current_date_val FROM dual;
よく誤用される予約語の例
-- 以下はOracleの予約語または特別な意味を持つキーワード
-- 列名・エイリアスにそのまま使うと問題が起きやすい

-- LEVEL    → 階層問い合わせの疑似列
-- ROWNUM   → 疑似列
-- ROWID    → 疑似列
-- DATE     → データ型
-- NUMBER   → データ型
-- VARCHAR2 → データ型
-- COMMENT  → 予約語
-- TABLE    → 予約語
-- FROM     → 予約語

-- 確認方法: 以下のビューで予約語一覧を確認
SELECT keyword, reserved
FROM v$reserved_words
WHERE reserved = 'Y'
ORDER BY keyword;

パターン:INSERT・UPDATE 文での列名ミス

INSERT や UPDATE の列名部分に誤りがあると ORA-00904 が発生します。特にORMやアプリケーションから動的に生成されるSQLで見落とされやすいです。

NG: INSERT の列名が存在しない
-- テーブルに emp_name という列は存在しない(正しくは last_name)
INSERT INTO employees (employee_id, emp_name, department_id)
VALUES (999, 'テスト', 10);
-- → ORA-00904: "EMP_NAME": 無効な識別子です
OK: 正しい列名を使う
-- USER_TAB_COLUMNS で列名を確認してから実行
INSERT INTO employees (employee_id, last_name, department_id)
VALUES (999, 'テスト', 10);
NG: UPDATE の SET 句で列名ミス
-- emplyee_id はスペルミス(正しくは employee_id)
UPDATE employees
SET emplyee_id = 1000
WHERE employee_id = 999;
-- → ORA-00904: "EMPLYEE_ID": 無効な識別子です

パターン:サブクエリ内での外部列の参照範囲外参照

相関サブクエリを使う際、参照できる列のスコープを誤ると ORA-00904 が発生します。

NG: サブクエリ内でスコープ外の列を参照
-- d はサブクエリの外にある別のブロックのエイリアス
-- サブクエリ内で参照できないスコープの列を使っている
SELECT e.employee_id, e.last_name
FROM employees e
WHERE e.salary > (
    SELECT AVG(salary)
    FROM departments d    -- ここで定義した d は
    WHERE d.department_id = e.department_id  -- ← e は外側のエイリアスなので参照可
      AND location_id = d.location_id        -- ← d はサブクエリ内なので参照可
);
注意が必要な構造:WITH 句でのエイリアス参照
-- WITH 句で定義したエイリアスは、その後の SELECT 内でのみ有効
WITH dept_avg AS (
    SELECT department_id, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
)
-- dept_avg は以下の SELECT で参照可能
SELECT e.employee_id, e.last_name, d.avg_salary
FROM employees e
JOIN dept_avg d ON e.department_id = d.department_id
WHERE e.salary > d.avg_salary;

列名・テーブル名を確認するSQL

ORA-00904 が発生したら、まず実際のオブジェクト定義を確認することが解決への近道です。

列名・データ型を確認する
-- 自分のスキーマのテーブル列情報
SELECT column_name, data_type, data_length, data_precision, data_scale, nullable
FROM user_tab_columns
WHERE table_name = 'テーブル名(大文字)'
ORDER BY column_id;

-- 他のスキーマのテーブルも含めて確認
SELECT owner, table_name, column_name, data_type
FROM all_tab_columns
WHERE table_name = 'テーブル名(大文字)'
ORDER BY owner, table_name, column_id;
テーブル・ビュー名を確認する
-- 自分のスキーマのテーブル・ビュー一覧
SELECT object_name, object_type, status
FROM user_objects
WHERE object_type IN ('TABLE', 'VIEW')
ORDER BY object_type, object_name;

-- テーブル名があいまいな場合はLIKEで絞り込む
SELECT object_name, object_type
FROM user_objects
WHERE object_name LIKE '%EMP%'
ORDER BY object_name;
引用符付き識別子で作られた列名を確認する(大文字小文字の確認)
-- 列名の実際の格納状態を確認(大文字か小文字か混在か)
SELECT column_name
FROM user_tab_columns
WHERE table_name = 'TEST_TABLE'
ORDER BY column_id;
-- 結果が 'employee_id'(小文字)なら引用符付き識別子で作られている
-- 結果が 'EMPLOYEE_ID'(大文字)なら通常識別子で作られている

ORA-00904 の対処フロー

ORA-00904 が発生したら以下の順番で確認すると効率よく解決できます。

ORA-00904 解決チェックリスト

  1. エラーメッセージの識別子名を確認する(どの識別子が無効か)
  2. USER_TAB_COLUMNS または DESC で実際の列名を確認する
  3. 引用符付き識別子チェック:作成時にダブルクォートを使ったか確認。使っていれば参照時も同じ大文字小文字でクォートが必要
  4. エイリアスのスコープチェック:SELECT 列エイリアスを WHERE/GROUP BY で使っていないか確認
  5. テーブルエイリアスのチェック:エイリアス名を一貫して使えているか確認
  6. 予約語チェック:列名・エイリアスにOracleの予約語を使っていないか確認

まとめ

ORA-00904(無効な識別子です)は、識別子(列名・テーブル名・エイリアス)をOracleが認識できないときに発生するエラーです。

発生の多くはスペルミス・引用符付き識別子の大文字小文字不一致・SELECT エイリアスのスコープ誤りの3パターンに集約されます。USER_TAB_COLUMNSDESC コマンドで実際の列名を確認する習慣を持つことと、引用符付き識別子を使わないシンプルな命名規則を設計時に決めておくことが、再発防止の鍵です。

同じORAエラーシリーズとして、ORA-01722(数値が無効です)ORA-00001(一意制約違反)の解説も参考にしてください。