【Oracle】PLS-00201の原因と解決方法|identifier must be declared・識別子を宣言してください

【Oracle】PLS-00201の原因と解決方法|identifier must be declared・識別子を宣言してください Oracle

PLS-00201: identifier 'xxx' must be declared は、PL/SQLが参照した識別子を解決できない時に発生するコンパイルエラーです。識別子とは、変数名、定数名、パッケージ名、プロシージャ名、ファンクション名、型名、表名、列名、シノニム名などを指します。

単なるスペルミスだけでなく、宣言位置がスコープ外、別スキーマのオブジェクトをスキーマ修飾していない、必要な EXECUTE / SELECT 権限が直接付与されていない、シノニムがない、パッケージ仕様部に公開されていない、という理由でも発生します。

先に結論
PLS-00201が出たら、まずエラー行の識別子が「変数」「パッケージ」「型」「表・列」「シノニム」のどれかを分けます。変数なら宣言位置とスコープ、パッケージや型なら ALL_OBJECTSALL_TAB_PRIVS、表やビューなら存在・スキーマ名・直接権限を確認します。PL/SQLではロール経由の権限が効かない場面があるため、権限不足も必ず疑ってください。
スポンサーリンク

PLS-00201とは

Oracle公式の説明では、PLS-00201は「参照された識別子を宣言する必要がある」ことを示すエラーです。また、識別子を参照するには権限が必要であり、ストアドオブジェクトではロールではなく直接付与された権限が必要になる場合があります。

よくある表示は次のような形です。

表示例 よくある意味 最初に見る場所
PLS-00201: identifier 'V_NAME' must be declared 変数や定数が未宣言、またはスコープ外 DECLARE部、ブロック範囲
PLS-00201: identifier 'PKG_ORDER.SYNC' must be declared パッケージ名・サブプログラム名・権限の問題 ALL_OBJECTS / ALL_ARGUMENTS
PLS-00201: identifier 'MASTER_SCHEMA.UTIL_PKG' must be declared 別スキーマのパッケージが見えない GRANT EXECUTE / シノニム
PLS-00201 + ORA-06550 PL/SQLブロック内の識別子解決失敗 後続のPLS-00201行

PLS-00201でオブジェクトが見えない場合、権限不足なら ORA-01031の原因と対処、表やビューが見えない場合は ORA-00942の原因と解決方法 も近い内容です。

まず確認する順番

PLS-00201は原因の幅が広いため、エラーになった識別子の種類を先に分けると早いです。次の順番で確認します。

順番 確認すること 使うもの
1 エラー行と列番号 USER_ERRORS.LINE / POSITION
2 識別子の種類 変数、パッケージ、型、表、列、シノニム
3 ローカル宣言の有無 DECLARE部、パッケージ仕様部
4 スコープ外ではないか 内側/外側ブロック、ラベル
5 オブジェクトが存在するか ALL_OBJECTS / ALL_TABLES
6 直接権限があるか ALL_TAB_PRIVS / USER_TAB_PRIVS
7 シノニムやスキーマ修飾が必要か ALL_SYNONYMS

USER_ERRORSでエラー位置を確認する

ストアドプロシージャやパッケージのコンパイル時に出た場合は、まず USER_ERRORS で行番号と列番号を確認します。複数エラーがある場合は、先頭のPLS-00201が後続エラーの原因になっていることがあります。

user-errors-pls00201.sql
SELECT name,
       type,
       sequence,
       line,
       position,
       text
FROM user_errors
WHERE text LIKE '%PLS-00201%'
ORDER BY name, type, sequence;

コンパイルエラー全般の読み方は PL/SQLコンパイル時エラーとUSER_ERRORSの使い方 も参考になります。

変数や定数が未宣言のケース

最も単純な原因は、変数や定数を宣言していない、または宣言名と参照名が違うケースです。PL/SQLでは、利用する変数は DECLARE 部やブロック内で先に宣言しておく必要があります。

variable-not-declared.sql
-- NG: v_nameを宣言していない
BEGIN
  DBMS_OUTPUT.PUT_LINE(v_name);
END;
/
-- PLS-00201: identifier 'V_NAME' must be declared

-- OK: DECLARE部で宣言する
DECLARE
  v_name VARCHAR2(100) := 'Alice';
BEGIN
  DBMS_OUTPUT.PUT_LINE(v_name);
END;
/

DBMS_OUTPUT の使い方や SET SERVEROUTPUT ON については DBMS_OUTPUTの使い方 も確認してください。

スコープ外の変数を参照しているケース

宣言しているのにPLS-00201になる場合は、スコープ外から参照している可能性があります。内側ブロックで宣言した変数は、外側ブロックからは見えません。

scope-error.sql
DECLARE
  v_outer NUMBER := 10;
BEGIN
  DECLARE
    v_inner NUMBER := 20;
  BEGIN
    DBMS_OUTPUT.PUT_LINE(v_outer + v_inner); -- OK
  END;

  DBMS_OUTPUT.PUT_LINE(v_inner); -- NG: ここでは見えない
END;
/
-- PLS-00201: identifier 'V_INNER' must be declared

同名変数が内側と外側にある場合は、内側の宣言が優先されます。外側を明示したい場合はブロックラベルを使う方法もあります。

パッケージやプロシージャが見えないケース

別スキーマのパッケージやプロシージャを呼ぶ時は、スキーマ修飾、存在確認、EXECUTE権限を確認します。名前が正しくても、実行ユーザーから見えなければPLS-00201になります。

package-exists-and-grants.sql
-- 呼び出し先が見えるか確認
SELECT owner, object_name, object_type, status
FROM all_objects
WHERE object_name = 'UTIL_PKG'
ORDER BY owner, object_type;

-- EXECUTE権限があるか確認
SELECT owner, table_name, privilege, grantee
FROM all_tab_privs
WHERE table_name = 'UTIL_PKG'
ORDER BY owner, grantee, privilege;

-- 付与する例(所有者側で実行)
GRANT EXECUTE ON master_schema.util_pkg TO app_schema;

呼び出し元がストアドプロシージャやパッケージの場合、ロール経由の権限ではなく直接付与された権限が必要になることがあります。SQL Developerで手動実行できるのに、パッケージのコンパイルではPLS-00201になる典型パターンです。

ユーザー定義TYPEが見えないケース

オブジェクト型、コレクション型、パッケージ内の型を引数や変数で使う時にもPLS-00201が出ます。特に別スキーマで定義されたTYPEを使う場合は、型そのものへの EXECUTE 権限と、正しいスキーマ修飾が必要です。

type-privilege-check.sql
-- 型が存在するか確認
SELECT owner, object_name, object_type, status
FROM all_objects
WHERE object_name IN ('ORDER_REC_TYPE', 'ORDER_TAB_TYPE')
  AND object_type IN ('TYPE', 'TYPE BODY')
ORDER BY owner, object_type, object_name;

-- TYPEへのEXECUTE権限を確認
SELECT owner, table_name, privilege, grantee
FROM all_tab_privs
WHERE table_name IN ('ORDER_REC_TYPE', 'ORDER_TAB_TYPE')
ORDER BY owner, table_name, grantee;

-- 付与例
GRANT EXECUTE ON master_schema.order_rec_type TO app_schema;
GRANT EXECUTE ON master_schema.order_tab_type TO app_schema;

パッケージ仕様部の引数に別スキーマのTYPEを使っている場合、呼び出し側にもそのTYPEが見えている必要があります。パッケージ本体だけでなく、公開インターフェースで使う型の権限も確認してください。

%TYPEや%ROWTYPEで別スキーマを参照するケース

プロシージャ引数や変数宣言で table.column%TYPEtable%ROWTYPE を使う場合、その表や列をコンパイル時に解決できないとPLS-00201になります。別スキーマの表を参照するなら、スキーマ修飾と直接SELECT権限が必要です。

percent-type-check.sql
-- NGになりやすい例: 表が見えない、または列名が違う
CREATE OR REPLACE PROCEDURE p_sync_customer(
  p_customer_id IN master_schema.customers.customer_id%TYPE
) AS
BEGIN
  NULL;
END;
/

-- 確認: 表と列が見えるか
SELECT owner, table_name, column_name, data_type
FROM all_tab_columns
WHERE owner = 'MASTER_SCHEMA'
  AND table_name = 'CUSTOMERS'
  AND column_name = 'CUSTOMER_ID';

-- 権限付与例
GRANT SELECT ON master_schema.customers TO app_schema;

%TYPE は便利ですが、参照先の表や列が変更されるとコンパイルエラーになります。列名が違う場合は ORA-00904、表や権限が問題なら ORA-00942 の観点でも確認します。

AUTHID DEFINER / CURRENT_USERと権限の違い

PL/SQLの権限問題では、AUTHID DEFINERAUTHID CURRENT_USER の違いも重要です。デフォルトのDefiner Rightsでは、定義者の権限で名前解決・実行され、ロール権限が効かない場面があります。Invoker Rightsでは、実行者側の権限や名前解決の影響を受けます。

方式 権限の見え方 PLS-00201で見ること
AUTHID DEFINER 定義者の直接権限が中心 所有者に直接GRANTされているか
AUTHID CURRENT_USER 実行者の権限・名前解決が影響 実行ユーザーで対象が見えるか
ロール経由権限 手動SQLでは見えることがある ストアドオブジェクトのコンパイルでは不足することがある
authid-example.sql
-- Invoker Rightsの例
CREATE OR REPLACE PROCEDURE p_list_customers
AUTHID CURRENT_USER
AS
BEGIN
  FOR r IN (SELECT customer_id FROM customers) LOOP
    NULL;
  END LOOP;
END;
/

-- 実行ユーザーごとに customers の解決先や権限が変わる点に注意

権限設計が絡む場合は、手動実行できるかだけでなく、どのユーザーでコンパイル・実行しているかを分けて確認します。

パッケージ仕様部に公開されていないケース

パッケージ本体の中にプロシージャが存在していても、仕様部に宣言されていなければ外部から呼び出せません。外部公開したいサブプログラムは、PACKAGE 仕様部に宣言します。

package-spec-public.sql
-- 仕様部: sync_orderだけ公開
CREATE OR REPLACE PACKAGE pkg_order AS
  PROCEDURE sync_order;
END pkg_order;
/

-- 本体: private_helperは本体内だけで使える
CREATE OR REPLACE PACKAGE BODY pkg_order AS
  PROCEDURE private_helper IS
  BEGIN
    NULL;
  END;

  PROCEDURE sync_order IS
  BEGIN
    private_helper;
  END;
END pkg_order;
/

-- 外部から pkg_order.private_helper は呼べない
-- PLS-00201 になる

表やビューが見えないケース

PL/SQL内で別スキーマの表やビューを参照していてPLS-00201になることもあります。この場合は、スキーマ修飾、存在確認、直接SELECT権限を見ます。

table-view-check.sql
-- 表やビューが見えるか確認
SELECT owner, object_name, object_type, status
FROM all_objects
WHERE object_name = 'CUSTOMERS'
  AND object_type IN ('TABLE', 'VIEW')
ORDER BY owner, object_type;

-- 権限付与例
GRANT SELECT ON master_schema.customers TO app_schema;

-- PL/SQL内ではスキーマ修飾して参照
SELECT customer_name
INTO v_name
FROM master_schema.customers
WHERE customer_id = p_customer_id;

列名ミスなら ORA-00904、表やビューの存在・権限問題なら ORA-00942 の切り分けも参考になります。

シノニムで解決できていないケース

シノニムを使う設計では、シノニムが存在しない、違う実体を向いている、実体への権限がない、という理由でPLS-00201になることがあります。シノニムは名前解決を助けますが、権限付与の代わりにはなりません。

synonym-check.sql
SELECT owner,
       synonym_name,
       table_owner,
       table_name,
       db_link
FROM all_synonyms
WHERE synonym_name IN ('UTIL_PKG', 'CUSTOMERS')
ORDER BY owner, synonym_name;

-- シノニムを作成する例
CREATE SYNONYM app_schema.util_pkg FOR master_schema.util_pkg;

-- ただしEXECUTE権限も必要
GRANT EXECUTE ON master_schema.util_pkg TO app_schema;

DBMS_OUTPUTでPLS-00201になるケース

DBMS_OUTPUT.PUT_LINE でPLS-00201になる場合、単純なスペルミス、実行ユーザーの権限、または環境差で DBMS_OUTPUT パッケージが参照できない可能性があります。通常の環境ではPUBLICにEXECUTE権限がありますが、制限された環境では確認が必要です。

dbms-output-check.sql
-- スペル確認: DBMS_OUTPUT.PUT_LINE が正しい
BEGIN
  DBMS_OUTPUT.PUT_LINE('test');
END;
/

-- 権限確認
SELECT owner, table_name, privilege, grantee
FROM all_tab_privs
WHERE table_name = 'DBMS_OUTPUT'
ORDER BY grantee, privilege;

ORA-06550と一緒に出る場合

PLS-00201は、匿名ブロックやストアドオブジェクトのコンパイル時に ORA-06550 と一緒に出ることが多いです。この場合、ORA-06550はPL/SQL全体の失敗を示す入口で、直すべきなのは後続のPLS-00201です。

ora-06550-pls00201.sql
BEGIN
  unknown_pkg.run;
END;
/

-- ORA-06550: line 2, column 3:
-- PLS-00201: identifier 'UNKNOWN_PKG.RUN' must be declared
-- ORA-06550: line 2, column 3:
-- PL/SQL: Statement ignored

よくある原因と対処一覧

原因 確認すること 対処
変数が未宣言 DECLARE部にあるか 変数・定数を宣言する
スコープ外 内側ブロックの変数を外側から見ていないか 宣言位置を上げる、または引数で渡す
パッケージ名・サブプログラム名ミス ALL_OBJECTS / ALL_PROCEDURES 正しい名前・スキーマ修飾に直す
パッケージ仕様部に未公開 PACKAGE仕様部に宣言があるか 仕様部に公開宣言を追加する
直接権限不足 ALL_TAB_PRIVS 所有者から直接GRANTする
シノニム不足 ALL_SYNONYMS シノニム作成と実体への権限付与
表・ビューが見えない ALL_OBJECTS / 権限 スキーマ修飾、SELECT権限付与

本番障害時の調査SQLセット

本番でPLS-00201が出た場合は、エラーメッセージに出ている識別子をもとに、存在、権限、シノニムを確認します。以下はパッケージや表を疑う時の調査SQLです。

pls-00201-investigation.sql
DEFINE obj_name = 'UTIL_PKG'

SELECT owner, object_name, object_type, status
FROM all_objects
WHERE object_name = UPPER('&obj_name')
ORDER BY owner, object_type;

SELECT owner, table_name, privilege, grantee
FROM all_tab_privs
WHERE table_name = UPPER('&obj_name')
ORDER BY owner, grantee, privilege;

SELECT owner, synonym_name, table_owner, table_name, db_link
FROM all_synonyms
WHERE synonym_name = UPPER('&obj_name')
ORDER BY owner, synonym_name;

PLS-00201と関連エラーの違い

エラー 意味 見るべき場所
PLS-00201 識別子が宣言されていない、または見えない 宣言、スコープ、権限、シノニム
ORA-06550 PL/SQLブロック全体の失敗を示す入口 後続の PLS- エラー
PLS-00905 参照しているオブジェクトが無効 USER_ERRORS
ORA-01031 権限不足 直接GRANTと実行ユーザー
ORA-00942 表またはビューが存在しない、または見えない 存在、スキーマ修飾、SELECT権限
ORA-00904 列名や識別子がSQLとして無効 列名、別名、引用符、大文字小文字

オブジェクトが無効化されている場合は PLS-00905の原因と解決方法、呼び出し先が実行時に使えない場合は ORA-06508の原因と解決方法 も確認してください。

修正チェックリスト

項目 確認内容 OKの状態
エラー位置 行番号・列番号を見たか 対象識別子が特定できている
宣言 変数や定数をDECLARE部で宣言したか 参照前に宣言済み
スコープ ブロック外から見えない変数を参照していないか 参照範囲内にある
パッケージ 仕様部に公開宣言があるか 外部呼び出し可能
存在 ALL_OBJECTS に対象があるか 想定スキーマに存在
権限 直接GRANTされているか EXECUTE/SELECTが直接付与済み
シノニム 正しい実体を向いているか 解決先と権限が一致

よくある質問

SELECTできるのにPL/SQLでPLS-00201になります

ロール経由の権限でSELECTできている可能性があります。ストアドプロシージャやパッケージでは、対象表やパッケージへの直接権限が必要になることがあります。

パッケージ内のプロシージャが見つかりません

パッケージ本体だけでなく、仕様部に宣言されているか確認してください。仕様部にないサブプログラムは外部から呼べません。

DBMS_OUTPUT.PUT_LINEでPLS-00201になります

まずスペルを確認します。特殊な権限制限がある環境では、DBMS_OUTPUT へのEXECUTE権限も確認してください。

シノニムを作れば解決しますか?

名前解決には役立ちますが、権限付与の代わりにはなりません。シノニム作成に加えて、実体オブジェクトへのEXECUTEやSELECT権限が必要です。

ORA-06550も一緒に出ています

ORA-06550はPL/SQLブロック全体の失敗を示す入口です。後続のPLS-00201に出ている識別子を直してください。

まとめ

PLS-00201は、PL/SQLが識別子を解決できない時に発生します。原因は、変数の未宣言、スコープ外参照、パッケージ仕様部に未公開、名前ミス、別スキーマ参照、直接権限不足、シノニム不足などです。

対応は、エラー行の識別子を特定し、ローカル宣言とスコープを確認し、オブジェクトなら ALL_OBJECTS、権限なら ALL_TAB_PRIVS、シノニムなら ALL_SYNONYMS を確認する流れです。PL/SQLではロール経由ではなく直接GRANTが必要になる場面があるため、権限不足を早めに疑うと解決が早くなります。

参考

PLS-00201 – Oracle Database Error Help

Coding PL/SQL Subprograms and Packages – Oracle Database Development Guide

ALL_ERRORS – Oracle Database Reference