【完全ガイド】ORA-00904: invalid identifier の原因と解決方法|列名タイプミス・予約語・引用符・エイリアス誤用まで徹底解説
- 作成日 2026.07.28
- Oracle Database
Oracle 開発者が最も頻繁に遭遇するエラー:
SELECT employee_name FROM employees;
-- ORA-00904: "EMPLOYEE_NAME": invalid identifier
**「そんな列ないよ」**とオラクルが言っている。しかし、実際には:
- 列名は合っているのに発生
- タイプミスしていないのに発生
- 他のクエリでは動くのに発生
- 開発環境では動くのに本番で発生
WHEREで列名エイリアスを使いたいINSERT時に列がない- 予約語を使ってしまった
- 引用符付き列名の case-sensitive
- エイリアスの誤用(別テーブル)
- 末尾の余分なカンマ
このエラーが厄介なのは、メッセージだけでは原因が特定できない点。「invalid identifier」= 「無効な識別子」と言われても:
- 列名なのか
- テーブル名なのか
- エイリアスなのか
- 予約語なのか
が分からない。さらに、引用符付き識別子の case-sensitivity など、Oracle 特有の罠があります:
-- ハマるケース
CREATE TABLE t ("createdAt" DATE); -- 引用符付き
SELECT createdAt FROM t; -- ORA-00904!
-- Oracle は CREATEDAT に大文字化して検索
-- しかし実際の列名は "createdAt"(大文字小文字保持)
SELECT "createdAt" FROM t; -- OK(引用符必須)
このため、Rails / Java / Django 等の外部フレームワークから作られた列名(キャメルケース)で問題が起きます。
さらに、SELECT では動くのに WHERE で使うと ORA-00904 になるエイリアスの罠:
SELECT employee_id AS emp_id
FROM employees
WHERE emp_id = 100;
-- ORA-00904: "EMP_ID": invalid identifier
-- WHERE は AS より前に評価される!
本記事では、ORA-00904: invalid identifier の完全な原因と解決方法を、リファレンスとして実用的に整理します。ORA-00942/00918/00979 との違い、10大発生パターン、診断方法、5つの解決策、引用符付き識別子の完全解説、予約語一覧、エイリアス評価順、Rails/Java/Python 対応、実践シナリオ、FAQまで完全網羅。この1本で ORA-00904 を根本から解決できるようになります。
- 1. 結論:まず列名を確認
- 2. 【原因①】列名タイプミス(最頻出)
- 3. 【原因②】存在しない列
- 4. 【原因③】引用符付き識別子(case-sensitivity)
- 5. 【原因④】予約語
- 6. 【原因⑤】WHERE でエイリアス使用(超頻出の罠)
- 7. 【原因⑥】別テーブルのエイリアス誤用
- 8. 【原因⑦】INSERT で存在しない列
- 9. 【原因⑧】CREATE TABLE の末尾カンマ
- 10. 【原因⑨】スキーマ違い
- 11. 【原因⑩】動的 SQL のミス
- 12. 診断ツール完全リファレンス
- 13. Rails / Java / Python 対応
- 14. 実践シナリオ
- 15. トラブルシューティング
- 16. よくある質問(FAQ)
- 17. 参考リンク
- 18. まとめ
結論:まず列名を確認
時間がない方向けに、最速の対処を先に示します。
エラーメッセージの読み方
ORA-00904: "EMPLOYEE_NAME": invalid identifier
↑ ここが問題の識別子
大文字化されている
→ 実際は "employee_name" or "employeeName"?
Oracle は引用符なし識別子を大文字化して検索。
最速の診断
-- ① 実際の列名確認
SELECT column_name, data_type
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES' -- 大文字!
ORDER BY column_id;
-- ② スキーマ違いなら
SELECT owner, column_name
FROM all_tab_columns
WHERE table_name = 'EMPLOYEES';
-- ③ DESCRIBE(対話的)
DESCRIBE employees;
10大原因
| # | 原因 | 症状 |
|---|---|---|
| ① | 列名タイプミス | 単純ミス |
| ② | 存在しない列 | 該当列がない |
| ③ | 引用符付き識別子 | case-sensitive |
| ④ | 予約語 | LEVEL, COMMENT 等 |
| ⑤ | WHERE でエイリアス使用 | 評価順の問題 |
| ⑥ | 別テーブルのエイリアス | JOIN で混同 |
| ⑦ | INSERT で存在しない列 | スキーマ違い |
| ⑧ | 末尾の余分なカンマ | CREATE TABLE |
| ⑨ | スキーマ違い | 環境問題 |
| ⑩ | 動的 SQL のミス | 文字列連結 |
ORA-00904 vs ORA-00942/00918/00979
| エラー | 対象 |
|---|---|
| ORA-00942 | テーブル/ビュー不存在 |
| ORA-00918 | 列名が曖昧(JOIN で同名) |
| ORA-00979 | GROUP BY 式なし |
| ORA-00904 | 識別子が無効(列名等) |
SQL構文4部作のエラーは相互に類似しますが、発生タイミングで区別。
詳細は以下で解説します。
【原因①】列名タイプミス(最頻出)
症状
SELECT * FROM employees WHERE empoyee_id = 100;
-- ORA-00904: "EMPOYEE_ID": invalid identifier
-- ↑ empoyee_id(typo)ではなく employee_id
診断
DESCRIBE employees;
-- または
SELECT column_name FROM user_tab_columns
WHERE table_name = 'EMPLOYEES';
解決
タイプミス修正:
SELECT * FROM employees WHERE employee_id = 100;
IDE / SQL Developer 使用でオートコンプリート活用。
【原因②】存在しない列
症状
SELECT employee_name FROM employees;
-- ORA-00904: 実際の列は 'first_name' と 'last_name'
診断
-- 全カラム確認
SELECT column_name FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'
ORDER BY column_id;
解決
正しい列名で:
SELECT first_name || ' ' || last_name AS employee_name
FROM employees;
【原因③】引用符付き識別子(case-sensitivity)
Oracle の識別子ルール
引用符なし: 大文字化して保存・検索
CREATE TABLE t (name VARCHAR2(50));
-- 内部的には TABLE T (NAME VARCHAR2(50))
SELECT name FROM t; -- OK
SELECT NAME FROM t; -- OK
SELECT Name FROM t; -- OK(全て NAME に変換)
引用符付き: 大文字小文字保持
CREATE TABLE t ("name" VARCHAR2(50));
-- 実際に "name" として保存
SELECT name FROM t; -- ORA-00904(NAME を探す)
SELECT "name" FROM t; -- OK
SELECT "NAME" FROM t; -- ORA-00904(大文字違い)
Rails / Django 由来の落とし穴
-- Rails マイグレーションで作成
CREATE TABLE users ("createdAt" TIMESTAMP);
-- SQL Developer 等で参照
SELECT createdAt FROM users;
-- ORA-00904: "CREATEDAT": invalid identifier
-- ↑ 大文字化されて検索、実際は "createdAt"
-- 正しい書き方
SELECT "createdAt" FROM users;
診断:実際の列名確認
SELECT column_name FROM user_tab_columns
WHERE table_name = 'USERS';
-- 結果:
-- ID
-- createdAt ← 引用符なしで小文字表示 = case-sensitive
-- updatedAt
**混在(大文字と小文字)**が case-sensitive の兆候。
解決
引用符で囲む:
SELECT "createdAt", "updatedAt" FROM users;
または列名を変更(推奨):
ALTER TABLE users RENAME COLUMN "createdAt" TO created_at;
【原因④】予約語
症状
CREATE TABLE t (
id NUMBER,
level NUMBER -- LEVEL は予約語!
);
-- ORA-00904
-- または
SELECT level FROM t;
-- 意図しない解釈(LEVEL は疑似列)
主要な予約語
SELECT, FROM, WHERE, GROUP, ORDER, BY, HAVING
INSERT, UPDATE, DELETE, MERGE
CREATE, ALTER, DROP, TABLE, INDEX, VIEW
NUMBER, VARCHAR2, DATE, TIMESTAMP
LEVEL, COMMENT, AUDIT, ROWID, ROWNUM
UID, USER, SESSION, SIZE, VALUES
全予約語確認
SELECT keyword FROM v$reserved_words
WHERE reserved = 'Y'
ORDER BY keyword;
解決
A. 別の列名にする(推奨):
CREATE TABLE t (
id NUMBER,
hierarchy_level NUMBER
);
B. 引用符で強制的に使う:
CREATE TABLE t (
id NUMBER,
"LEVEL" NUMBER
);
SELECT "LEVEL" FROM t; -- 引用符必須
推奨は A(引用符は保守困難)。
【原因⑤】WHERE でエイリアス使用(超頻出の罠)
症状
SELECT employee_id AS emp_id
FROM employees
WHERE emp_id = 100;
-- ORA-00904: "EMP_ID": invalid identifier
原因:SQL の評価順序
1. FROM → テーブル特定
2. WHERE → 行フィルタ
3. GROUP BY
4. HAVING
5. SELECT → ここで AS 評価
6. ORDER BY → AS 使用可
WHERE は SELECT より前に評価、AS を知らない。
解決
A. 元の列名を使う:
SELECT employee_id AS emp_id
FROM employees
WHERE employee_id = 100;
B. サブクエリで包む:
SELECT * FROM (
SELECT employee_id AS emp_id FROM employees
) WHERE emp_id = 100;
C. WITH(CTE)で分離:
WITH aliased AS (
SELECT employee_id AS emp_id FROM employees
)
SELECT * FROM aliased WHERE emp_id = 100;
ORDER BY / HAVING でのエイリアス
-- ✅ ORDER BY は AS 使える(SELECT より後)
SELECT employee_id AS emp_id FROM employees
ORDER BY emp_id;
-- ✅ HAVING は同じテーブル/GROUP BY の列
SELECT department_id, COUNT(*) AS cnt
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 10; -- HAVING で AS 直接使用は不可
GROUP BY 関連の詳細は ORA-00979: not a GROUP BY expression の記事も参照してください。
【原因⑥】別テーブルのエイリアス誤用
症状
SELECT a.test_name
FROM example_tab b;
-- ORA-00904: "A"."TEST_NAME": invalid identifier
-- ↑ エイリアス 'a' は存在しない
症状(JOIN)
SELECT o.order_id, c.customer_id
FROM orders o JOIN customers c ON o.customer_id = c.customer_id
WHERE o.status = 'active'
AND cust.region = 'ASIA'; -- 'cust' 未定義!
-- ORA-00904: "CUST"."REGION": invalid identifier
解決
正しいエイリアスを使う:
SELECT o.order_id, c.customer_id
FROM orders o JOIN customers c ON o.customer_id = c.customer_id
WHERE o.status = 'active'
AND c.region = 'ASIA'; -- ✅ c を使用
【原因⑦】INSERT で存在しない列
症状
INSERT INTO employees (emp_id, name, salary)
VALUES (100, 'John', 50000);
-- ORA-00904: 実際の列は 'employee_id', 'first_name', ...
診断
-- テーブルの全列と NULL 可否
SELECT column_name, data_type, nullable
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES';
解決
正しい列名で:
INSERT INTO employees (employee_id, first_name, salary)
VALUES (100, 'John', 50000);
NOT NULL 関連は ORA-01400: cannot insert NULL の記事も参照してください。
【原因⑧】CREATE TABLE の末尾カンマ
症状(見つけにくい)
CREATE TABLE t (
id NUMBER,
name VARCHAR2(50), -- ← 末尾のカンマ
);
-- ORA-00904 or ORA-00907
解決
カンマを削除:
CREATE TABLE t (
id NUMBER,
name VARCHAR2(50) -- カンマなし
);
同様に発生する場所:
- INSERT の VALUES リスト
- SELECT の列リスト
【原因⑨】スキーマ違い
症状
開発では動く、本番で ORA-00904:
開発: schema_dev.employees.mgr_id 列あり
本番: schema_prod.employees.manager_id 列名違い
診断
-- 現在のスキーマ確認
SELECT USER FROM DUAL;
-- 特定オブジェクトの全スキーマ確認
SELECT owner, table_name
FROM all_tables
WHERE table_name = 'EMPLOYEES';
解決
マイグレーション同期:
- Rails: db/migrate/
- Java: Flyway / Liquibase
- Python: Alembic / Django migrations
バージョン管理を徹底。
Rails 8 系の詳細は Rails 8 アップグレードガイドの記事、rails db:migrate 使い方の記事、pending migration エラーの記事も参照してください。
【原因⑩】動的 SQL のミス
症状
DECLARE
v_col_name VARCHAR2(30) := 'name';
v_sql VARCHAR2(1000);
v_result VARCHAR2(100);
BEGIN
v_sql := 'SELECT ' || v_col_name || ' FROM employees WHERE id = 100';
EXECUTE IMMEDIATE v_sql INTO v_result;
END;
/
-- ORA-00904: 'name' は存在しない、実際は 'first_name'
解決
列名検証:
-- 動的 SQL の前に列存在確認
DECLARE
v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'
AND column_name = UPPER(v_col_name);
IF v_count = 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'Column not found');
END IF;
-- 続行
END;
/
バインド変数 or whitelist で安全な動的 SQL。
診断ツール完全リファレンス
USER_TAB_COLUMNS
-- 自スキーマのテーブル
SELECT column_name, data_type, data_length, nullable
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'
ORDER BY column_id;
ALL_TAB_COLUMNS
-- アクセス可能な全スキーマ
SELECT owner, table_name, column_name
FROM all_tab_columns
WHERE column_name = 'EMPLOYEE_ID';
DBA_TAB_COLUMNS(DBA権限)
SELECT owner, table_name, column_name
FROM dba_tab_columns
WHERE column_name LIKE '%SALARY%';
DESCRIBE
DESCRIBE employees;
-- または
DESC employees;
SQL*Plus / SQLcl / SQL Developer で対話的に確認。
V$RESERVED_WORDS
-- 予約語一覧
SELECT keyword, reserved, res_type
FROM v$reserved_words
WHERE reserved = 'Y'
ORDER BY keyword;
Rails / Java / Python 対応
Rails ActiveRecord
列名規則:
# Rails のマイグレーション
create_table :employees do |t|
t.string :employee_name # 通常の列名(大文字化される)
t.timestamps # created_at, updated_at
end
oracle_enhanced adapter:
# デフォルトで snake_case → UPPER_CASE
# Rails の created_at → Oracle の CREATED_AT
手動マイグレーションで引用符使用は避ける:
# ❌ 避ける
execute 'CREATE TABLE t ("createdAt" TIMESTAMP)'
# ✅ Rails 標準
create_table :t do |t|
t.timestamps
end
エラーハンドリング:
begin
Employee.where("employee_name = ?", "John").to_a
rescue ActiveRecord::StatementInvalid => e
if e.message.include?("ORA-00904")
Rails.logger.error "無効な列名: #{e.message}"
end
end
Rails 8 系の詳細は Rails 8 アップグレードガイドの記事、find/find_by/where の記事、Solid Queue 使い方の記事も参照してください。
Java (JDBC)
try {
stmt.executeQuery("SELECT emp_id FROM employees");
} catch (SQLException e) {
if (e.getErrorCode() == 904) {
logger.error("Invalid identifier: " + e.getMessage());
// 列名確認クエリを実行
try (Statement s = conn.createStatement();
ResultSet rs = s.executeQuery(
"SELECT column_name FROM user_tab_columns " +
"WHERE table_name = 'EMPLOYEES'"
)) {
while (rs.next()) {
System.out.println(rs.getString(1));
}
}
}
}
Python (oracledb)
import oracledb
try:
cursor.execute("SELECT emp_id FROM employees")
except oracledb.DatabaseError as e:
error_obj, = e.args
if error_obj.code == 904:
print(f"Invalid identifier: {error_obj.message}")
# 列名確認
cursor.execute("""
SELECT column_name FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'
""")
columns = [row[0] for row in cursor]
print(f"Available: {columns}")
SQLAlchemy:
from sqlalchemy import inspect
inspector = inspect(engine)
columns = inspector.get_columns('employees')
for col in columns:
print(col['name'])
実践シナリオ
シナリオ1:新機能開発時の列追加漏れ
-- 1. エラー確認
SELECT column_name FROM user_tab_columns
WHERE table_name = 'ORDERS';
-- 2. 必要な列を追加
ALTER TABLE orders ADD (
tracking_number VARCHAR2(50),
delivered_at TIMESTAMP
);
-- 3. マイグレーションファイル作成
-- Rails: rails g migration AddTrackingToOrders
-- Java: Flyway V2__add_tracking.sql
シナリオ2:本番でのみ発生する ORA-00904
-- 本番と開発のスキーマ差分確認
SELECT column_name FROM all_tab_columns
WHERE owner = 'PROD_SCHEMA' AND table_name = 'EMPLOYEES'
MINUS
SELECT column_name FROM all_tab_columns
WHERE owner = 'DEV_SCHEMA' AND table_name = 'EMPLOYEES';
シナリオ3:引用符付き列名の一括修正
-- 引用符付き列を検出
SELECT table_name, column_name
FROM user_tab_columns
WHERE REGEXP_LIKE(column_name, '[a-z]'); -- 小文字を含む
-- 一括で標準化
BEGIN
FOR rec IN (
SELECT table_name, column_name
FROM user_tab_columns
WHERE REGEXP_LIKE(column_name, '[a-z]')
) LOOP
EXECUTE IMMEDIATE
'ALTER TABLE ' || rec.table_name ||
' RENAME COLUMN "' || rec.column_name ||
'" TO ' || UPPER(rec.column_name);
END LOOP;
END;
/
シナリオ4:Rails での列名 case-sensitive 問題
# 問題: 他システムから接続してきた Rails
class Employee < ApplicationRecord
self.table_name = 'EMPLOYEES'
# 引用符付き列の場合
# config/application.rb で設定
# config.active_record.schema_migrations_table_name = ...
end
# 対処: マイグレーションで列名変更
class RenameCreatedAt < ActiveRecord::Migration[8.0]
def change
rename_column :employees, :createdAt, :created_at
end
end
シナリオ5:WHERE エイリアスの罠を回避
-- ❌ よくあるミス
SELECT department_id AS dept_id, COUNT(*) AS cnt
FROM employees
WHERE dept_id > 10 -- ORA-00904
GROUP BY dept_id; -- ORA-00904
-- ✅ CTE で解決
WITH aliased AS (
SELECT department_id AS dept_id, employee_id
FROM employees
)
SELECT dept_id, COUNT(*) AS cnt
FROM aliased
WHERE dept_id > 10
GROUP BY dept_id;
分析関数の詳細は Oracle 分析関数(OVER/PARTITION BY)の記事も参照してください。
シナリオ6:予約語を含む既存 DB のリファクタリング
-- 予約語列を検出
SELECT c.table_name, c.column_name
FROM user_tab_columns c
JOIN v$reserved_words r ON c.column_name = r.keyword
WHERE r.reserved = 'Y';
-- 例: LEVEL 列を hierarchy_level に
ALTER TABLE t RENAME COLUMN "LEVEL" TO hierarchy_level;
シナリオ7:Docker Oracle での開発
# Docker で列名確認
docker exec -it oracle-xe sqlplus scott/tiger <<EOF
DESC employees;
EOF
Docker 関連は docker daemon 接続エラーの記事、Docker no space left on device の記事も参照してください。
シナリオ8:Data Pump 後の列名確認
# Data Pump インポート後の列名確認
impdp system/pw dumpfile=data.dmp tables=employees
# 列名が期待通りか
sqlplus system/pw <<EOF
DESC employees;
SELECT column_name FROM user_tab_columns WHERE table_name = 'EMPLOYEES';
EOF
Data Pump の詳細は Oracle Data Pump 使い方の記事を参照してください。
シナリオ9:ORM のマイグレーション同期
# CI/CD パイプラインでの列名検証
- name: Check schema
run: |
sqlplus $DB_USER/$DB_PASSWORD@$DB_HOST <<EOF
SELECT column_name FROM user_tab_columns
WHERE table_name IN ('USERS', 'ORDERS')
ORDER BY table_name, column_id;
EOF
Kamal 2 デプロイの詳細は Kamal 2 デプロイの記事を参照してください。
シナリオ10:ANSI JOIN と (+) の混在
-- 古いスタイル (+)
SELECT o.order_id, c.customer_name
FROM orders o, customers c
WHERE o.customer_id = c.customer_id(+);
-- ANSI JOIN に書き換え時
SELECT o.order_id, c.customer_name
FROM orders o LEFT JOIN customers c ON o.customer_id = c.customer_id;
-- USING 使用時の落とし穴
SELECT o.order_id, customer_id -- customer_id は無修飾必須
FROM orders o JOIN customers c USING (customer_id);
-- SELECT o.customer_id → ORA-25154 (USING 列に修飾禁止)
トラブルシューティング
エラーメッセージが空
ORA-00904: : invalid identifier
識別子部分が空:
- 末尾のカンマ
- 空の列リスト
- SQL の途中で切れている
開発では動く、本番で失敗
- スキーマ差分
- マイグレーション未適用
- 権限違い(列が見えない)
DDL 実行後に発生
-- キャッシュされた SQL が古い
ALTER TABLE t ADD col NUMBER;
-- 直後にアプリで col が見つからない場合
-- → コネクションプール再作成
引用符付き識別子の混乱
-- 引用符あり列の検出
SELECT * FROM user_tab_columns
WHERE table_name = 'YOUR_TABLE'
AND column_name != UPPER(column_name);
-- 小文字を含む = case-sensitive
CTE / サブクエリで発生
-- CTE 内で別名を使い、外側で元の名前を参照
WITH t AS (SELECT id AS renamed_id FROM src)
SELECT id FROM t; -- ORA-00904(renamed_id を使う)
同義語(Synonym)の問題
-- Synonym が別のテーブルを指している
SELECT synonym_name, table_owner, table_name
FROM user_synonyms;
よくある質問(FAQ)
Q1. 大文字と小文字の区別
- 引用符なし: 区別なし(全て大文字化)
- 引用符あり: 完全一致必須
Q2. 引用符付き列名の推奨
推奨しない。保守困難。標準化して引用符なしに。
Q3. WHERE で AS 使いたい
不可(評価順のため)。CTE / サブクエリで対応。
Q4. 予約語一覧
SELECT keyword FROM v$reserved_words WHERE reserved = 'Y';
Q5. Rails での対処
rename_column マイグレーションで標準化。
Q6. ORA-00904 vs ORA-00942
- 00904: 列名(識別子)
- 00942: テーブル/ビュー
Q7. ORA-00904 vs ORA-00918
- 00904: 列が存在しない
- 00918: 列名が曖昧(同名複数)
Q8. 動的 SQL での対策
事前に列名検証、バインド変数活用。
Q9. USING と ON の使い分け
- USING: 同名列を結合、SELECT で修飾禁止
- ON: 任意の結合条件
Q10. Autonomous DB での挙動
同じ。引用符付き列名は推奨されない。
Q11. ORA-00904 の英語メッセージ
ORA-00904: string: invalid identifier
string に実際の識別子が入る。
Q12. IDEでの回避策
SQL Developer / DataGrip でオートコンプリート活用。
参考リンク
Oracle 公式
- Oracle Database Error Messages: ORA-00904
- Oracle Database SQL Language Reference: Database Object Naming Rules
- USER_TAB_COLUMNS View
- V$RESERVED_WORDS
まとめ
ORA-00904: invalid identifier の要点を再整理します。
エラーの本質
Oracle が SQL 中の識別子(列名等)を解決できない
→ 存在しない or 見つけられない
エラーメッセージの読み方
ORA-00904: "IDENTIFIER": invalid identifier
↑ 大文字化された名前
→ 元の SQL の名前を確認
→ 大文字化で変わるなら引用符問題
4部作の SQL 構文エラー
| エラー | 意味 |
|---|---|
| ORA-00942 | テーブル/ビュー不存在 |
| ORA-00918 | 列名が曖昧 |
| ORA-00979 | GROUP BY 式なし |
| ORA-00904 | 識別子が無効 |
10大原因
| # | 原因 | 対処 |
|---|---|---|
| ① | 列名タイプミス | 修正 |
| ② | 存在しない列 | 実列名確認 |
| ③ | 引用符付き識別子 | 引用符付けるか rename |
| ④ | 予約語 | 別名 or 引用符 |
| ⑤ | WHERE エイリアス | 元名 or CTE |
| ⑥ | 別テーブルエイリアス | 正しいエイリアス |
| ⑦ | INSERT 存在しない列 | 実列名確認 |
| ⑧ | 末尾のカンマ | 削除 |
| ⑨ | スキーマ違い | 環境同期 |
| ⑩ | 動的 SQL ミス | 検証 |
診断クエリ
-- ① 列名確認
SELECT column_name FROM user_tab_columns
WHERE table_name = 'TABLE_NAME';
-- ② 全スキーマ検索
SELECT owner, table_name FROM all_tab_columns
WHERE column_name = 'COLUMN_NAME';
-- ③ 予約語検索
SELECT keyword FROM v$reserved_words WHERE reserved = 'Y';
-- ④ 引用符付き検出
SELECT * FROM user_tab_columns
WHERE column_name != UPPER(column_name);
エイリアス評価順
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
WHERE: AS 使えない
ORDER BY: AS 使える
HAVING: 集約関数直接
引用符付き識別子
-- ❌ 保守困難
CREATE TABLE t ("createdAt" TIMESTAMP);
SELECT "createdAt" FROM t; -- 引用符必須
-- ✅ 標準化
CREATE TABLE t (created_at TIMESTAMP);
SELECT created_at FROM t; -- 引用符不要
これらの知識は、Oracle での SQL 開発・デバッグ・データ移行・スキーマ設計・Rails / Java / Python 開発・マイグレーション管理・本番トラブル対応など、あらゆる場面で活用できます。本記事をブックマークしておけば、ORA-00904 に出会っても冷静に的確に対処できるようになります。
本記事は2026年6月時点の情報をもとに、Oracle Database 19c〜23ai での動作確認・公式ドキュメントに基づき作成しています。Oracle のバージョンにより挙動が異なる場合があるため、最新の情報は Oracle 公式ドキュメント(docs.oracle.com)もあわせてご確認ください。
-
前の記事
【完全ガイド】Oracle EXPLAIN PLAN 見方 徹底解説|DBMS_XPLAN・実行計画の読み方・チューニング 2026.07.28
-
次の記事
【完全ガイド】ORA-02292: integrity constraint (child record found) の原因と解決方法|親削除・CASCADE・階層削除 徹底解説 2026.07.29
コメントを書く