PL/SQL(およびOracle SQL)には、言語仕様で特別な意味を持つ予約語が500語以上あります。DATE/TYPE/LEVEL/COUNTといったつい使いたくなる名前は全て予約語で、v_dateではなくdateを変数名にするとPLS-00103 / ORA-00923エラーでコンパイルが通りません。
入門記事の多くは「こんな単語は使うな」という一覧だけで終わっていますが、実務では予約語(Reserved Words)とキーワード(Keywords)の違い、V$RESERVED_WORDSで最新リストを確認する方法、引用符囲み識別子("ORDER")の挙動、レガシーテーブルで既に予約語列を持ってしまった場合の対処、事故多発TOP10の予約語など、深い知識が必要です。
この記事ではPL/SQLの予約語をカテゴリ別500語以上でカバーし、予約語誤用時のエラーメッセージ、引用符囲み識別子の完全解説、実務で事故るTOP10予約語(LEVEL/COUNT/DATE/TYPE/NAME等)、レガシー対処パターン、命名規則ベストプラクティスまで網羅した決定版です。関連する【PL/SQL】IF文完全ガイド/【PL/SQL】例外処理完全ガイド/【PL/SQL】変数・定数完全ガイドと併読推奨。
この記事で学べること
- 予約語(Reserved)とキーワード(Keyword)の違い
V$RESERVED_WORDSビューで最新予約語を調べる方法- カテゴリ別予約語一覧(11カテゴリ500語以上)
- PL/SQL特有の予約語(
EXCEPTION/PRAGMA/%TYPE等) - 実務で事故るTOP10予約語(
LEVEL/COUNT/DATE/TYPE等) - 引用符囲み識別子(
"Order")の罠 - 誤用時のエラーメッセージ集(PLS-00103等)
- 変数名の正しい命名規則(
v_プレフィックス/名詞・動詞) - 予約語列を持つレガシーテーブルの対処法
- 2026年版のベストプラクティスチェックリスト
30秒クイックリファレンス:予約語とは
-- ❌ 予約語を変数名にするとコンパイルエラー DECLARE date DATE; -- DATEは予約語 count NUMBER; -- COUNTは予約語(キーワード) level NUMBER; -- LEVELも要注意 BEGIN date := SYSDATE; -- PLS-00103: 識別子 "DATE" が必要 END; -- ⭕ プレフィックスで回避 DECLARE v_date DATE; v_count NUMBER; v_level NUMBER; BEGIN v_date := SYSDATE; END;
3つの黄金律:①変数名にv_プレフィックスを必ず付ける、②テーブル列名も予約語を避ける(引用符回避のため)、③使うならV$RESERVED_WORDSで最新予約語を確認してから。
V$RESERVED_WORDSで予約語を確認
-- Oracle 12c以降は V$RESERVED_WORDS ビューで全予約語を一覧可能 SELECT keyword, length, reserved, res_type, res_attr, res_semi, duplicate FROM V$RESERVED_WORDS WHERE reserved = 'Y' ORDER BY keyword; -- 列の意味 -- reserved: 'Y'=予約語(厳格)、'N'=非予約だが特殊用途あり -- res_type: 'Y'=データ型として予約 -- res_attr: 'Y'=属性として予約 -- res_semi: 'Y'=セミ予約(一部構文で使用可能) -- duplicate: 'Y'=重複(複数の役割を持つ)
予約語 vs キーワード:違いを理解する
Oracleのドキュメントで「reserved words」と「keywords」は別のカテゴリです。どちらも変数名に使うと問題が起きますが、制約の強さが違うのが重要なポイント。
-- 予約語は絶対NG DECLARE begin NUMBER; -- PLS-00103: 識別子 "begin" が不正 BEGIN NULL; END; -- キーワードは文脈依存でエラーが出たり出なかったり DECLARE date NUMBER; -- 状況によってはコンパイル通るがSELECT内で衝突 BEGIN SELECT TO_CHAR(date, 'YYYY-MM-DD') INTO ...; -- ここでエラー END; -- 非予約(標準関数名)は上書き可能だが危険 DECLARE FUNCTION substr(...) RETURN VARCHAR2 IS ...; -- 標準SUBSTRが隠蔽される BEGIN -- 以降この変数内では独自substrが呼ばれる NULL; END;
実務では一律「避ける」
予約語・キーワード・非予約の境界は複雑で、Oracleバージョンごとに変わります。実務では「特別な意味を持つ単語」を一律避けるのが最も安全。v_プレフィックスを付ける運用なら意識する必要すらなくなります。
カテゴリ別予約語一覧
実務で使う予約語を11カテゴリに分類しました。PL/SQL固有のものと、Oracle SQL共通のものが混在する点に注意。
①ブロック構造・宣言
②制御フロー(IF / LOOP / CASE)
③カーソル関連
④データ型
⑤論理演算・比較
⑥DML(データ操作)
⑦DDL(定義操作)
⑧トランザクション
⑨問い合わせ修飾
⑩例外・コンパイラ指令
⑪権限・セキュリティ
実務で事故るTOP10予約語・キーワード
「うっかり使いたくなる」名前なのに予約語/キーワードだった、という実務で最頻出の10単語を集めました。
① DATE → v_date, order_date, created_dt ② COUNT → v_count, total_count, row_cnt ③ LEVEL → v_level, depth, priority_level ④ TYPE → v_type, record_type, kind ⑤ NAME → v_name, full_name, display_name ⑥ NUMBER → v_number, order_number, no ⑦ ROWNUM → v_rownum, seq_no ⑧ TIMESTAMP → v_ts, updated_ts ⑨ VALUE → v_value, attr_value ⑩ SIZE → v_size, dimension
TOP10の詳細解説
-- ❌ テーブル列名に DATE を使うと引用符必須 CREATE TABLE events ( id NUMBER, date DATE -- ORA-00904 ); -- ⭕ 意味のある列名に CREATE TABLE events ( id NUMBER, event_date DATE, -- 具体的な意味を持つ名前 created_at TIMESTAMP, updated_at TIMESTAMP );
DATE/NAME/TYPE/COUNT は Oracle コードの No.1 事故源。これら4つは他言語/他DBでは普通に変数名になるため、Oracle初心者がほぼ必ず踏む罠。プロジェクト規約で「DATEで終わる列名/変数名は使わない、_dateまたは_atにする」と決めておくと衝突事故が激減します。
引用符囲み識別子:”ORDER”の罠
Oracleはダブルクォート("...")で囲むと予約語でも識別子にできますが、ケースセンシティブ(大小文字区別)になり様々な副作用が生まれます。基本的に避けるのが正解です。
-- ❌ 引用符で予約語を使う(非推奨) CREATE TABLE orders ( id NUMBER, "DATE" DATE, -- 引用符必須になる "ORDER" VARCHAR2(10) ); -- 以降も常に引用符が必要 SELECT "DATE", "ORDER" FROM orders; -- 引用符無しはエラー -- 大小文字区別の罠 CREATE TABLE t ( "Name" VARCHAR2(100), -- 登録名は Name(PascalCase) "name" VARCHAR2(100) -- 別列として共存可能 ); SELECT name FROM t; -- Oracleは大文字化してNAMEを探す→ORA-00904 SELECT "Name" FROM t; -- これなら動く
引用符識別子の3つのデメリット
①ケースセンシティブの強制:一度"Name"で作ると、以降のSELECTでも必ず同じケースで引用符付き指定が必要。通常のname指定(Oracleが大文字化してNAMEを探す)では見つからない。
②ツール互換性の問題:ORM/マイグレーションツール/BI ツールが引用符識別子を正しく扱えずエラーを出すことがある。GUI ツールでテーブル操作できない場合も。
③保守性が著しく低下:他の開発者がDATE列の存在を知らずSELECT date FROM tと書いて毎回エラー。チームメンバー全員が規約を知らないと混乱が広がる。
-- 既存 "User Name" 列を扱う(レガシーDB対応) DECLARE v_name VARCHAR2(100); BEGIN SELECT "User Name" INTO v_name FROM legacy_users WHERE id = 1; UPDATE legacy_users SET "User Name" = 'New Name' WHERE id = 1; END;
予約語誤用時のエラーメッセージ集
-- ①PLS-00103: 識別子 "BEGIN" が必要 DECLARE begin NUMBER; -- 予約語を変数名に BEGIN NULL; END; -- Error at line 2: PLS-00103 -- ②ORA-00904: 無効な識別子 SELECT date FROM events; -- date列は引用符必須 -- ORA-00904: "DATE": invalid identifier -- ③ORA-00936: 式がありません SELECT FROM users; -- 列指定忘れ or 予約語衝突 -- ④PLS-00201: 識別子を宣言してください DECLARE v_name VARCHAR2(100); BEGIN username := 'taro'; -- 宣言していない識別子 END; -- ⑤ORA-00957: 列名が重複 CREATE TABLE t ( id NUMBER, id NUMBER -- 重複(予約語との衝突でも発生しうる) ); -- ⑥ORA-00942: 表またはビューが存在しません SELECT * FROM "ORDER"; -- 大小文字違いで別名扱い -- 実際は ORDER テーブル(大文字)で登録されているが引用符で小文字指定している
エラーメッセージの読み方のコツ:①PLS-XXXXXはPL/SQLコンパイル時エラー、②ORA-XXXXXはSQL実行時エラー、③“XXXが必要” は予約語誤用の可能性、④“invalid identifier” はカラム名/変数名のタイポか予約語衝突、⑤行番号はUSER_ERRORSビューで詳細確認可能。
変数名・識別子の命名規則
安全な命名規則
-- ⭕ プロジェクト標準の命名規則
DECLARE
-- 変数(Variable):v_
v_count NUMBER;
v_user_name VARCHAR2(100);
v_order_date DATE;
-- パラメータ(Parameter):p_
PROCEDURE update_user(
p_id NUMBER,
p_status VARCHAR2
) IS ...
-- 定数(Constant):c_
c_tax_rate CONSTANT NUMBER := 0.10;
c_max_retry CONSTANT NUMBER := 3;
-- 例外(Exception):e_
e_not_found EXCEPTION;
e_invalid EXCEPTION;
-- 型(Type):t_
TYPE t_ids IS TABLE OF NUMBER;
TYPE t_user IS RECORD (...);
-- カーソル(Cursor):cur_
CURSOR cur_active_users IS
SELECT id, email FROM users WHERE status = 'active';
-- グローバル変数(Global、パッケージ):g_
g_session_id VARCHAR2(100);
g_debug_mode BOOLEAN := FALSE;
BEGIN
NULL;
END;
命名規則ベストプラクティス
①全ての変数・パラメータにプレフィックス(v_/p_等)を付ける、②列名との衝突を防ぐ(WHERE id = p_idのように識別)、③意味のある名前(v_xよりv_user_count)、④スネークケース(v_user_count)がOracle業界標準、⑤最大30文字(12cR2未満)または128文字(12cR2+)制限に注意、⑥ASCII英数字+アンダースコアのみ(多バイト文字や記号は引用符必須になる)。詳細は【PL/SQL】変数・定数完全ガイドの命名規則セクション参照。
レガシーテーブルに予約語列がある時の対処
既に稼働している業務システムで、過去の設計者がDATEやTYPEを列名に使ってしまった場合の現実的な対処法です。
-- ①現在のスキーマ確認 SELECT column_name FROM user_tab_columns WHERE table_name = 'ORDERS' ORDER BY column_id; -- ② 予約語列の使用は引用符で SELECT id, "DATE", "TYPE" FROM orders; -- ③ PL/SQL変数に取り込む時は%TYPEで型継承 DECLARE v_date orders."DATE"%TYPE; v_type orders."TYPE"%TYPE; BEGIN SELECT "DATE", "TYPE" INTO v_date, v_type FROM orders WHERE id = 1; END; -- ④ 可能ならビューで別名を付けて上位アプリから隠す CREATE OR REPLACE VIEW v_orders AS SELECT id, "DATE" AS event_date, "TYPE" AS event_type FROM orders; -- 以降、v_ordersを使えば予約語に触れない SELECT event_date, event_type FROM v_orders WHERE id = 1; -- ⑤ 最終解:リネーム(サービス停止で計画) ALTER TABLE orders RENAME COLUMN "DATE" TO event_date; ALTER TABLE orders RENAME COLUMN "TYPE" TO event_type;
ビューで予約語を隠蔽するメリット
- 上位アプリは引用符なしのクリーンな列名でアクセスできる
- 将来の物理リネームへの移行が容易(ビュー定義だけ書き換えればOK)
- 既存システムを壊さず段階的に移行
- ORM(Hibernate/MyBatis/Entity Framework等)との互換性向上
2026年版ベストプラクティスチェックリスト
よくある質問
V$RESERVED_WORDSビューで確認できます。SELECT keyword, length, reserved, res_type FROM V$RESERVED_WORDS ORDER BY keyword;で予約語属性付きの完全リストが取得できます。公式ドキュメント「Oracle Database SQL Language Reference」の「Oracle SQL Reserved Words」章でも確認可能。PL/SQL特有の予約語は「Oracle Database PL/SQL Language Reference」を参照してください。DECLARE date DATE; BEGIN date := SYSDATE; END;はPLS-00103: Encountered the symbol "DATE"でコンパイル失敗。解決策はv_dateのようにプレフィックスを付けるか、意味のある別名(order_date)に変更。"DATE" DATE, "COUNT" NUMBERのように定義可能ですが、以降常に引用符が必要になり可読性と保守性が大きく下がります。event_date、total_countのように意味を明確にした複合名にするのがベストプラクティス。"Name"と"name"は別)、②毎回引用符必須(SQL文・PL/SQL内で引用符忘れるとエラー)、③ORM/ツール互換性問題(一部ツールが引用符識別子を扱えない)、④可搬性低下(他DB移行時に書き換え大量発生)。実務では絶対に使わないのが正解です。"ユーザーID")、ツール/ORM/クラウド移行での互換性問題が山積み。識別子はASCII英数字+アンダースコアのみが国際標準です。DECLARE sysdate NUMBER; BEGIN sysdate := 10; ... END;のようにすると、そのスコープ内で標準関数SYSDATEが隠蔽されバグの温床になります。v_sysdateやcurrent_timeのように別名を使いましょう。V$RESERVED_WORDSと照合するのが確実ですが、一般的なプレフィックス(pkg_)を付ければ衝突しません。例:pkg_user_service、pkg_order_queue。Oracle純正パッケージはDBMS_/UTL_プレフィックスを使うので、ユーザーコードはpkg_で区別するのが実務慣行。_で始まる名前はOracle内部用途と衝突の恐れ。必ず英字で始めるのが安全。JSON_TABLE(12.1)、MATCH_RECOGNIZE(12.1)、LATERAL(12.1)、BLOCKCHAIN(21c)など。既存コードがアップグレードで予約語衝突することがあるため、V$RESERVED_WORDSでバージョンごとに確認するのが確実です。SELECT column_name FROM user_tab_columns WHERE table_name = 'ORDERS';で実際の列名を確認するのが第一歩。関連記事
- 【PL/SQL】IF文完全ガイド — IF/THEN/ELSIF等の制御キーワード
- 【PL/SQL】例外処理完全ガイド — EXCEPTION/RAISE/PRAGMAの使い方
- 【PL/SQL】ループ処理完全ガイド — LOOP/FOR/EXIT/CONTINUE
- 【PL/SQL】カーソル完全ガイド — CURSOR/OPEN/FETCH/CLOSE
- 【PL/SQL】変数・定数完全ガイド — 変数宣言と命名規則
- 【PL/SQL】初心者でもわかる基本構文とブロック構造の書き方 — DECLARE/BEGIN/EXCEPTION/END
- 【PL/SQL】ストアドプロシージャとファンクションの違いと作り方 — PROCEDURE/FUNCTION/AS/IS
- 【PL/SQL】IN・OUT・IN OUTパラメータの完全ガイド — パラメータモードキーワード
- 【PL/SQL】パッケージを使ったコード管理と再利用性向上 — PACKAGE/BODY
まとめ
- PL/SQL予約語は500語以上、
V$RESERVED_WORDSビューで全件確認可能 - 予約語(Reserved)/キーワード(Keyword)/非予約の3階層がある
- カテゴリ別では11種:ブロック/制御/カーソル/データ型/論理演算/DML/DDL/トランザクション/問い合わせ/例外/権限
- TOP10事故予約語:
DATE/COUNT/LEVEL/TYPE/NAME/NUMBER/ROWNUM/TIMESTAMP/VALUE/SIZE - 引用符囲み識別子(
"...")はケースセンシティブ強制+ツール非互換で実務では絶対禁止 - 誤用時のエラー:PLS-00103/ORA-00904/ORA-00936
- 命名規則:
v_/p_/c_/e_/t_/g_/cur_/pkg_プレフィックスで衝突回避 - 列名は
_date/_at/_typeで終わる複合名に - レガシー対処:ビューで別名付与→段階的に
ALTER TABLE RENAME COLUMN - 識別子はASCII英数字+アンダースコアのみ、128バイト以下(12cR2+)
PL/SQLの予約語は「なんとなく避けるもの」から「なぜ予約語なのか」「どう確認し・どう命名するか」まで理解することで、バグを未然に防ぎ、保守性の高いコードが書けます。本記事の11カテゴリリスト・TOP10事故予約語・ベストプラクティスチェックリストをプロジェクトのコーディング規約に組み込めば、予約語由来のバグは激減します。基本構文は基本構文ガイド、変数は変数・定数完全ガイド、例外は例外処理完全ガイドと組み合わせて活用してください。

