【完全ガイド】PLS-00201: identifier must be declared の原因と解決方法|ロール経由権限の罠・DBMS_LOCK・シノニム 徹底解説
- 作成日 2026.08.12
- Oracle Database
Oracle PL/SQL 開発者・DBA が必ず一度は遭遇するコンパイルエラー:
Warning: Procedure created with compilation errors.
SQL> SHOW ERRORS
Errors for PROCEDURE MY_PROC:
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/3 PL/SQL: Statement ignored
5/3 PLS-00201: identifier 'DBMS_LOCK.SLEEP' must be declared
「識別子が宣言されていない」というシンプルなメッセージ。しかし、実際には極めて多岐にわたる原因があり、特に**「権限はあるはずなのに失敗する」というロール経由権限の罠**が Oracle 特有の悪名高い問題として知られています:
- 未宣言の変数(初学者頻出)
- 変数名のスペルミス
- スコープ外の参照
GRANT EXECUTE権限不足- シノニム不足(
DBMS_LOCK,DBMS_SYSTEM等) - ロール経由の権限(コンパイル時無効)← 最も難解な罠
- 予約語との衝突
- 引用符付き識別子(case-sensitive)
- パッケージ本体で外部参照
- INVALID オブジェクトへの参照
このエラーはPL/SQL コンパイル時に発生するため、SQL 実行時の ORA-00904 (invalid identifier) とは根本的に異なります:
PLS-00201: PL/SQL コンパイル時(オブジェクト作成/変更時)
ORA-00904: SQL 実行時(クエリ実行時)
ORA-06550: PL/SQL 実行時(無名ブロック等)
現場では、特にエンタープライズシステムで**「昨日まで動いていたのに」**と嘆く典型的エラーです:
シナリオ: E-Business Suite でパッケージ再コンパイル
Warning: Package Body altered with compilation errors.
PLS-00201: identifier 'SYS.DBMS_SYS_SQL' must be declared
多くの日本語記事が「変数を宣言せよ」で終わりますが、実務では:
GRANT EXECUTEが必要な場合- ロール経由の権限は無効というOracle の重要な原則
DEFINER'S RIGHTSvsINVOKER'S RIGHTS(AUTHID)- シノニム作成(
DBMS_LOCK,DBMS_SYSTEM,DBMS_SYS_SQL) ALTER USER ... GRANT CONNECT THROUGHの活用- ORA-06550 との併発の解釈
- Rails / Java アプリでの発生
- CI/CD パイプラインでの事前検出
さらに、Oracle の “ロール経由権限がコンパイル時に効かない” ルールは、多くの開発者を深い混乱に陥れます:
-- APPL ユーザーで実行
-- ロール DEV_ROLE 経由で EXECUTE 権限がある
GRANT EXECUTE ON COMN.PRC_EOD TO DEV_ROLE;
GRANT DEV_ROLE TO APPL;
-- SQL 実行時は動く
BEGIN COMN.PRC_EOD; END; -- OK
-- でも PL/SQL 内で使うと失敗
CREATE PROCEDURE MY_PROC IS
BEGIN
COMN.PRC_EOD; -- PLS-00201
END;
/
「なぜ?」の答え: Oracle の PL/SQL コンパイルは、ロール経由の権限を無効化するため。直接権限が必須です。
本記事では、PLS-00201: identifier must be declared の完全な原因と解決方法を、リファレンスとして実用的に整理します。10大発生パターン、ORA-00904/ORA-06550 との違い、5つの解決策、DEFINER’S RIGHTS vs INVOKER’S RIGHTS、Rails/Java/Python 対応、実践シナリオ、FAQまで完全網羅。この1本で PLS-00201 を根本から解決できるようになります。
- 1. 結論:宣言 or 権限 が必要
- 2. PL/SQL コンパイル vs SQL 実行の違い
- 3. 【原因①】未宣言の変数(初学者頻出)
- 4. 【原因②】変数名のスペルミス
- 5. 【原因③】スコープ外の参照
- 6. 【原因④】ロール経由の権限(超危険な罠)
- 7. 【原因⑤】シノニム不足(DBMS_LOCK, DBMS_SYSTEM)
- 8. 【原因⑥】スキーマ違い
- 9. 【原因⑦】INVALID オブジェクト
- 10. 【原因⑧】DEFINER’S vs INVOKER’S RIGHTS
- 11. 【原因⑨】予約語との衝突
- 12. 【原因⑩】引用符付き識別子
- 13. 5つの解決策 完全リファレンス
- 14. Rails / Java / Python 対応
- 15. 実践シナリオ
- 16. トラブルシューティング
- 17. よくある質問(FAQ)
- 17.1. Q1. PLS-00201 と ORA-00904 の違い
- 17.2. Q2. なぜロール経由権限が効かない
- 17.3. Q3. AUTHID CURRENT_USER で解決?
- 17.4. Q4. DBMS_LOCK が使えない
- 17.5. Q5. Rails / Java での対応
- 17.6. Q6. 動的 SQL の使い所
- 17.7. Q7. INVALID オブジェクトの一括再コンパイル
- 17.8. Q8. E-Business Suite での典型パターン
- 17.9. Q9. 予防策
- 17.10. Q10. Autonomous DB での制約
- 17.11. Q11. パフォーマンスへの影響
- 17.12. Q12. パブリックシノニムの権限
- 18. 参考リンク
- 19. まとめ
結論:宣言 or 権限 が必要
時間がない方向けに、最速の対処を先に示します。
エラーメッセージの読み方
PLS-00201: identifier 'X' must be declared
↑
識別子 X が宣言されていない
= 未宣言 or 見えない
識別子の意味:
- 変数 / 定数
- プロシージャ / ファンクション / パッケージ
- テーブル / ビュー
- タイプ
最速の診断
-- ① オブジェクト存在確認
SELECT owner, object_name, object_type, status
FROM all_objects
WHERE object_name = UPPER('X');
-- ② 権限確認(直接権限のみ)
SELECT * FROM user_tab_privs
WHERE table_name = UPPER('X');
-- ③ シノニム確認
SELECT * FROM all_synonyms
WHERE synonym_name = UPPER('X');
5つの解決策
| # | 手法 | 使う場面 |
|---|---|---|
| ① | 変数宣言 | 未宣言変数 |
| ② | GRANT EXECUTE | 権限不足 |
| ③ | シノニム作成 | スキーマ違い |
| ④ | ロール → 直接権限 | ロール経由の罠 |
| ⑤ | スキーマプレフィックス | 明示的参照 |
3つの姉妹エラー
| エラー | タイミング | 意味 |
|---|---|---|
| PLS-00201 | PL/SQL コンパイル | 識別子未宣言 |
| ORA-00904 | SQL 実行時 | 列名等の識別子無効 |
| ORA-06550 | PL/SQL 実行時 | ライン/カラム位置 |
PLS-00201 は必ず ORA-06550 と併発(コンパイル時)。
詳細は以下で解説します。
PL/SQL コンパイル vs SQL 実行の違い
PLS-00201 発生タイミング
オブジェクト作成/変更時:
CREATE OR REPLACE PROCEDURE my_proc IS
BEGIN
DBMS_LOCK.SLEEP(1); -- ← PLS-00201 の可能性
END;
/
-- Warning: Procedure created with compilation errors.
無名ブロック実行時:
BEGIN
DBMS_LOCK.SLEEP(1); -- ← ORA-06550 + PLS-00201
END;
/
通常の SQL:
-- SQL 実行時は権限があれば動く
BEGIN COMN.PRC_EOD; END; -- OK(ロール経由でも)
決定的違い
SQL 実行時: ロール経由の権限で動く
PL/SQL コンパイル時: ロール経由の権限は無効
理由: PL/SQL は「事前コンパイル」される
ロールは動的、コンパイル時に決まらない
この違いが混乱の元。
【原因①】未宣言の変数(初学者頻出)
症状
DECLARE
v_id NUMBER;
BEGIN
SELECT id INTO v_id FROM t;
DBMS_OUTPUT.PUT_LINE(v_name); -- ← 未宣言
END;
/
-- PLS-00201: identifier 'V_NAME' must be declared
解決
DECLARE
v_id NUMBER;
v_name VARCHAR2(100); -- 宣言
BEGIN
SELECT id, name INTO v_id, v_name FROM t;
DBMS_OUTPUT.PUT_LINE(v_name);
END;
/
【原因②】変数名のスペルミス
症状
DECLARE
v_customer_name VARCHAR2(100);
BEGIN
v_costomer_name := 'John'; -- ← タイポ
END;
/
-- PLS-00201: identifier 'V_COSTOMER_NAME' must be declared
解決
タイポ修正、IDE のオートコンプリート活用。
【原因③】スコープ外の参照
症状
DECLARE
v_outer NUMBER;
BEGIN
DECLARE
v_inner NUMBER;
BEGIN
v_inner := 1;
END;
v_inner := 2; -- ← スコープ外
END;
/
-- PLS-00201
解決
スコープを意識:
DECLARE
v_outer NUMBER;
v_inner NUMBER; -- 外側で宣言
BEGIN
v_inner := 1;
v_inner := 2; -- OK
END;
/
【原因④】ロール経由の権限(超危険な罠)
シナリオ
-- SYS 側で権限付与
GRANT EXECUTE ON dbms_lock TO dev_role;
GRANT dev_role TO app_user;
-- app_user で確認
SELECT * FROM session_roles;
-- DEV_ROLE が有効
-- SQL 実行は OK
BEGIN dbms_lock.sleep(1); END;
/
-- 正常終了
-- PL/SQL コンパイルは失敗
CREATE OR REPLACE PROCEDURE my_proc IS
BEGIN
dbms_lock.sleep(1);
END;
/
-- PLS-00201: identifier 'DBMS_LOCK.SLEEP' must be declared
原因
Oracle の重要ルール:
PL/SQL コンパイル時は、ロール経由の権限が無効化される。直接権限のみ有効。
解決
直接権限を付与:
-- ロール経由でなく、ユーザーに直接
GRANT EXECUTE ON dbms_lock TO app_user;
-- これで PL/SQL コンパイルも動く
診断クエリ
-- 直接権限のみ
SELECT * FROM user_tab_privs
WHERE table_name = 'DBMS_LOCK';
-- ロール経由の権限
SELECT * FROM role_tab_privs
WHERE table_name = 'DBMS_LOCK';
-- こちらはあっても PL/SQL では無効
【原因⑤】シノニム不足(DBMS_LOCK, DBMS_SYSTEM)
症状
CREATE OR REPLACE PROCEDURE trace_enable IS
BEGIN
dbms_system.set_ev(...); -- ← PLS-00201
END;
/
原因
DBMS_SYSTEM は SYS スキーマ限定、パブリックシノニム未作成。
解決
-- SYS で実行
CREATE PUBLIC SYNONYM dbms_system FOR sys.dbms_system;
GRANT EXECUTE ON dbms_system TO app_user;
-- または PUBLIC 全体に
GRANT EXECUTE ON dbms_system TO PUBLIC;
同様のケース
DBMS_LOCK → シノニム + GRANT
DBMS_SYS_SQL → シノニム + GRANT
DBMS_SYSTEM → シノニム + GRANT
UTL_RAW → 通常はデフォルト有効
権限系は ORA-01031: insufficient privileges の記事も参照してください。
【原因⑥】スキーマ違い
症状
APPL ユーザーから COMN スキーマのプロシージャ:
-- APPL ユーザー
CREATE OR REPLACE PROCEDURE my_proc IS
BEGIN
prc_eod_processing; -- ← COMN.PRC_EOD_PROCESSING
END;
/
-- PLS-00201
解決A: スキーマプレフィックス
COMN.prc_eod_processing;
解決B: シノニム作成
-- APPL 側で
CREATE SYNONYM prc_eod_processing FOR comn.prc_eod_processing;
-- または PUBLIC
CREATE PUBLIC SYNONYM prc_eod_processing FOR comn.prc_eod_processing;
解決C: EXECUTE 権限
-- COMN 側で
GRANT EXECUTE ON prc_eod_processing TO appl;
【原因⑦】INVALID オブジェクト
症状
SELECT status FROM user_objects
WHERE object_name = 'MY_PKG';
-- INVALID
-- 使うと
BEGIN my_pkg.some_proc; END;
/
-- PLS-00201(見えない状態)
解決
再コンパイル:
ALTER PACKAGE my_pkg COMPILE;
ALTER PACKAGE my_pkg COMPILE BODY;
-- 一括
BEGIN
DBMS_UTILITY.COMPILE_SCHEMA('APPL');
END;
/
-- または
EXEC UTL_RECOMP.recomp_serial('APPL');
INVALID の詳細は ORA-04068: existing state of packages の記事も参照してください。
【原因⑧】DEFINER’S vs INVOKER’S RIGHTS
概念
DEFINER’S RIGHTS(デフォルト):
- パッケージ所有者の権限で実行
- 所有者に直接権限必要
INVOKER’S RIGHTS (AUTHID CURRENT_USER):
- 呼び出し元の権限で実行
- 動的な権限判定
例
-- DEFINER'S RIGHTS(デフォルト)
CREATE OR REPLACE PROCEDURE p1 IS
BEGIN
...
END;
/
-- INVOKER'S RIGHTS
CREATE OR REPLACE PROCEDURE p2 AUTHID CURRENT_USER IS
BEGIN
...
END;
/
使い分け
DEFINER'S:
✓ 通常のビジネスロジック
✓ 権限はパッケージ所有者に集中
INVOKER'S:
✓ 汎用ユーティリティ
✓ 複数スキーマから呼ばれる
✗ ロール経由でも動く(12c+)
【原因⑨】予約語との衝突
症状
DECLARE
level NUMBER := 1; -- ← LEVEL は疑似列
BEGIN
DBMS_OUTPUT.PUT_LINE(level);
END;
/
-- 意図と異なる、または PLS-00201
解決
変数名を変更:
DECLARE
v_level NUMBER := 1;
BEGIN
DBMS_OUTPUT.PUT_LINE(v_level);
END;
/
予約語関連は ORA-00904: invalid identifier の記事も参照してください。
【原因⑩】引用符付き識別子
症状
Rails マイグレーションで作成されたテーブル:
CREATE TABLE users ("createdAt" TIMESTAMP);
-- 引用符付き = case-sensitive
CREATE OR REPLACE PROCEDURE p IS
v_at users.createdAt%TYPE;
-- Oracle は CREATEDAT に大文字化して検索
-- しかし実列名は "createdAt"
BEGIN
...
END;
/
-- PLS-00201
解決
A. 引用符付きで参照:
v_at users."createdAt"%TYPE;
B. 列名を標準化(推奨):
ALTER TABLE users RENAME COLUMN "createdAt" TO created_at;
5つの解決策 完全リファレンス
解決策① 変数宣言
DECLARE
v_name VARCHAR2(100); -- 明示的宣言
BEGIN
v_name := 'John';
END;
/
解決策② GRANT EXECUTE
-- 直接権限(PL/SQL では必須)
GRANT EXECUTE ON dbms_lock TO app_user;
GRANT EXECUTE ON comn.prc_eod TO appl;
解決策③ シノニム作成
-- パブリック
CREATE PUBLIC SYNONYM dbms_lock FOR sys.dbms_lock;
-- プライベート
CREATE SYNONYM my_pkg FOR other_schema.my_pkg;
解決策④ ロール → 直接権限
-- ❌ ロール経由(PL/SQL 無効)
GRANT dev_role TO app_user;
GRANT EXECUTE ON dbms_lock TO dev_role;
-- ✅ 直接権限
GRANT EXECUTE ON dbms_lock TO app_user;
解決策⑤ スキーマプレフィックス
-- 明示的にスキーマ指定
comn.prc_eod_processing;
sys.dbms_lock.sleep(1);
Rails / Java / Python 対応
Rails ActiveRecord
ストアド呼び出し時のエラー:
begin
ActiveRecord::Base.connection.execute("BEGIN dbms_lock.sleep(1); END;")
rescue ActiveRecord::StatementInvalid => e
if e.message.include?("PLS-00201")
Rails.logger.error "権限またはシノニム不足: #{e.message}"
# 対処: DBA に GRANT EXECUTE 依頼
end
end
マイグレーションでの権限付与:
class GrantExecuteToApp < ActiveRecord::Migration[8.0]
def up
execute "GRANT EXECUTE ON dbms_lock TO app_user"
end
end
Rails 8 系の詳細は Rails 8 アップグレードガイドの記事、rails db:migrate 使い方の記事も参照してください。
Java (JDBC)
try {
stmt.execute("BEGIN dbms_lock.sleep(1); END;");
} catch (SQLException e) {
if (e.getMessage().contains("PLS-00201")) {
logger.error("権限不足: " + e.getMessage());
}
}
Python (oracledb)
import oracledb
try:
cursor.execute("BEGIN dbms_lock.sleep(1); END;")
except oracledb.DatabaseError as e:
error_obj, = e.args
if "PLS-00201" in error_obj.message:
print(f"権限不足: {error_obj.message}")
実践シナリオ
シナリオ1:本番デプロイ時の PLS-00201 対策
-- 事前チェックスクリプト
SELECT o.owner, o.object_name, o.object_type, o.status
FROM user_objects o
WHERE o.status = 'INVALID';
-- INVALID があれば再コンパイル
BEGIN
DBMS_UTILITY.COMPILE_SCHEMA('APP_USER');
END;
/
-- 権限確認
SELECT * FROM user_tab_privs
WHERE grantee = 'APP_USER'
AND privilege = 'EXECUTE';
シナリオ2:ロール経由権限のトラブルシューティング
-- 1. ロール経由の権限確認
SELECT * FROM role_tab_privs
WHERE table_name = 'DBMS_LOCK';
-- 2. 直接権限確認
SELECT * FROM user_tab_privs
WHERE table_name = 'DBMS_LOCK';
-- 3. 直接権限がなければ付与
GRANT EXECUTE ON dbms_lock TO app_user;
-- 4. 再コンパイル
ALTER PROCEDURE my_proc COMPILE;
シナリオ3:E-Business Suite での対処
-- APPS ユーザーで DBMS_SYSTEM 使う場合
SQL> CONN sys/pw AS SYSDBA
SQL> CREATE PUBLIC SYNONYM dbms_system FOR dbms_system;
SQL> GRANT EXECUTE ON dbms_system TO apps;
SQL> ALTER PACKAGE apps.fnd_trace COMPILE BODY;
-- コンパイル成功
シナリオ4:CI/CD パイプラインでの事前チェック
# .github/workflows/db-deploy.yml
- name: Compile check
run: |
sqlplus $DB_USER/$DB_PW <<EOF
ALTER PACKAGE my_pkg COMPILE BODY;
SHOW ERRORS
EOF
Kamal 2 デプロイの詳細は Kamal 2 デプロイの記事を参照してください。
シナリオ5:新スキーマ設定時のチェックリスト
-- スキーマ間の依存を全て EXECUTE 権限付与
BEGIN
FOR r IN (
SELECT owner, object_name, object_type
FROM all_objects
WHERE object_type IN ('PACKAGE', 'PROCEDURE', 'FUNCTION')
AND owner = 'COMN'
) LOOP
EXECUTE IMMEDIATE
'GRANT EXECUTE ON ' || r.owner || '.' || r.object_name ||
' TO appl';
END LOOP;
END;
/
シナリオ6:Rails マイグレーションで権限管理
class SetupPermissions < ActiveRecord::Migration[8.0]
def up
execute "GRANT EXECUTE ON dbms_lock TO app_user"
execute "GRANT EXECUTE ON dbms_utility TO app_user"
execute "GRANT EXECUTE ON dbms_stats TO app_user"
end
def down
execute "REVOKE EXECUTE ON dbms_lock FROM app_user"
# ...
end
end
シナリオ7:Docker Oracle での再現
docker exec -it oracle-xe sqlplus scott/tiger <<EOF
CREATE OR REPLACE PROCEDURE p IS
BEGIN
dbms_lock.sleep(1);
END;
/
SHOW ERRORS
EOF
Docker 関連は docker daemon 接続エラーの記事、Docker no space left on device の記事も参照してください。
シナリオ8:Java Spring での対処
@Configuration
public class OraclePermissionInit {
@Bean
public CommandLineRunner init(JdbcTemplate jdbc) {
return args -> {
try {
jdbc.execute("BEGIN dbms_lock.sleep(0); END;");
} catch (Exception e) {
if (e.getMessage().contains("PLS-00201")) {
logger.error("DBA に GRANT EXECUTE ON DBMS_LOCK 依頼");
}
}
};
}
}
シナリオ9:Autonomous DB での挙動
-- Autonomous DB では権限管理が制限的
-- 一部の SYS パッケージは admin ユーザーでも使えない
-- ADB 固有の代替方法を使う(DBMS_CLOUD 等)
シナリオ10:本番緊急対応
-- INVALID オブジェクトの一括再コンパイル
BEGIN
UTL_RECOMP.recomp_parallel(4, 'APP_SCHEMA');
END;
/
-- 権限の一括付与スクリプト
SELECT 'GRANT EXECUTE ON ' || object_name || ' TO app_user;' AS sql
FROM dba_objects
WHERE owner = 'SYS'
AND object_name IN ('DBMS_LOCK', 'DBMS_SYSTEM', 'DBMS_UTILITY')
AND object_type = 'PACKAGE';
トラブルシューティング
エラーが特定できない
SHOW ERRORS PACKAGE BODY my_pkg;
-- 行番号・列番号と共に表示
コンパイルは通るが実行時失敗
AUTHID CURRENT_USER の場合、呼び出し元の権限次第。
ロール経由権限の詳細確認
-- 現セッションのロール
SELECT * FROM session_roles;
-- 有効な権限
SELECT * FROM session_privs;
大文字小文字の混乱
-- 引用符付き列の検出
SELECT * FROM user_tab_columns
WHERE table_name = 'YOUR_TABLE'
AND column_name != UPPER(column_name);
動的 SQL での対処
動的 SQL は実行時判定、権限がロール経由でも OK:
EXECUTE IMMEDIATE 'BEGIN dbms_lock.sleep(1); END;';
-- ロール経由でも動く
PL/SQL 内で使いたければ動的 SQL も選択肢。
E-Business Suite での対応
Oracle 純正シノニム設定スクリプトを実行:
@?/rdbms/admin/utlrp.sql
よくある質問(FAQ)
Q1. PLS-00201 と ORA-00904 の違い
- PLS-00201: PL/SQL コンパイル時
- ORA-00904: SQL 実行時
Q2. なぜロール経由権限が効かない
PL/SQL は事前コンパイル、ロールは動的。コンパイル時に権限判定できない。
Q3. AUTHID CURRENT_USER で解決?
部分的に解決。ただし呼び出し元の権限次第。
Q4. DBMS_LOCK が使えない
SYSDBA でシノニム作成 + GRANT EXECUTEが必要。
Q5. Rails / Java での対応
DBA に権限依頼、または動的 SQL 活用。
Q6. 動的 SQL の使い所
ロール経由権限でも動く。パフォーマンスとの相談。
Q7. INVALID オブジェクトの一括再コンパイル
EXEC DBMS_UTILITY.COMPILE_SCHEMA('SCHEMA');
Q8. E-Business Suite での典型パターン
DBMS_SYSTEM, DBMS_SYS_SQL のシノニム/権限不足。
Q9. 予防策
- 直接権限付与
- 定期的な INVALID チェック
- CI/CD で事前検証
Q10. Autonomous DB での制約
一部の SYS パッケージ使用不可、DBMS_CLOUD 等の代替を使う。
Q11. パフォーマンスへの影響
コンパイルエラーは実行不能、パフォーマンス以前の問題。
Q12. パブリックシノニムの権限
創らないと駄目、GRANT EXECUTE だけでは不十分な場合あり。
参考リンク
Oracle 公式
- Oracle Database Error Messages: PLS-00201
- Oracle PL/SQL Language Reference: Definer’s Rights and Invoker’s Rights
- Oracle Database Security Guide: Roles
- DBMS_LOCK Package
まとめ
PLS-00201: identifier must be declared の要点を再整理します。
エラーの本質
PL/SQL コンパイル時に識別子が見つからない
→ 未宣言 or 見えない
→ 変数不足 or 権限不足 or スキーマ違い
エラーメッセージの読み方
PLS-00201: identifier 'X' must be declared
↑
識別子 X を宣言 or 権限付与
姉妹エラー
| エラー | タイミング |
|---|---|
| PLS-00201 | PL/SQL コンパイル |
| ORA-00904 | SQL 実行時 |
| ORA-06550 | PL/SQL 実行位置情報 |
10大原因
| # | 原因 | 対処 |
|---|---|---|
| ① | 未宣言変数 | 宣言 |
| ② | スペルミス | 修正 |
| ③ | スコープ外 | 外側で宣言 |
| ④ | ロール経由権限 | 直接権限 |
| ⑤ | シノニム不足 | CREATE SYNONYM |
| ⑥ | スキーマ違い | プレフィックス or シノニム |
| ⑦ | INVALID オブジェクト | 再コンパイル |
| ⑧ | DEFINER’S RIGHTS | AUTHID CURRENT_USER |
| ⑨ | 予約語 | 変数名変更 |
| ⑩ | 引用符付き識別子 | 引用符 or リネーム |
5つの解決策
-- ① 変数宣言
DECLARE v_x NUMBER;
-- ② GRANT EXECUTE(直接権限)
GRANT EXECUTE ON pkg TO user;
-- ③ シノニム作成
CREATE PUBLIC SYNONYM pkg FOR schema.pkg;
-- ④ ロール → 直接
-- ❌ GRANT role_x TO user;
-- ✅ GRANT EXECUTE ON pkg TO user;
-- ⑤ スキーマプレフィックス
schema.pkg.proc;
ロール経由権限の重要ルール
SQL 実行時: ロール経由 OK
PL/SQL コンパイル時: 直接権限のみ
→ PL/SQL でパッケージ使うなら直接権限必須
DEFINER’S vs INVOKER’S RIGHTS
-- DEFINER'S(デフォルト)
CREATE PROCEDURE p IS BEGIN ... END;
-- INVOKER'S
CREATE PROCEDURE p AUTHID CURRENT_USER IS BEGIN ... END;
INVOKER’S はロール経由権限で動く(12c+)。
診断クエリ
-- ① 存在確認
SELECT * FROM all_objects WHERE object_name = 'X';
-- ② 直接権限
SELECT * FROM user_tab_privs WHERE table_name = 'X';
-- ③ ロール経由権限
SELECT * FROM role_tab_privs WHERE table_name = 'X';
-- ④ INVALID
SELECT * FROM user_objects WHERE status = 'INVALID';
-- ⑤ シノニム
SELECT * FROM all_synonyms WHERE synonym_name = 'X';
DBMS_LOCK 使用の設定
-- SYS で
CREATE PUBLIC SYNONYM dbms_lock FOR sys.dbms_lock;
GRANT EXECUTE ON dbms_lock TO app_user;
-- または PUBLIC
予防のポイント
1. 直接権限付与を徹底
2. 定期的な INVALID チェック
3. CI/CD で事前コンパイル検証
4. 引用符付き識別子を避ける
5. IDE のオートコンプリート
6. スキーマ設計時に権限設計
7. AUTHID の意識的な使い分け
8. Rails マイグレーションで権限管理
9. 動的 SQL の選択肢
10. スキーマ間の依存最小化
これらの知識は、Oracle での PL/SQL 開発・DBA 業務・権限管理・E-Business Suite 運用・Rails / Java / Python アプリ運用・CI/CD パイプライン・本番デプロイなど、あらゆる場面で活用できます。本記事をブックマークしておけば、PLS-00201 に出会っても冷静に的確に対処できるようになります。
本記事は2026年6月時点の情報をもとに、Oracle Database 19c〜23ai での動作確認・公式ドキュメントに基づき作成しています。Oracle のバージョンにより挙動が異なる場合があるため、最新の情報は Oracle 公式ドキュメント(docs.oracle.com)もあわせてご確認ください。
-
前の記事
【完全ガイド】ORA-00913: too many values の原因と解決方法|INSERT・サブクエリ・タプル比較 徹底解説 2026.08.10
-
次の記事
【完全ガイド】ORA-06550 line/column: PLS-00320 の原因と解決方法|エラースタック・%TYPE・カスケードエラー 徹底解説 2026.08.15
コメントを書く