PL/SQLブロックに直接ddlステートメントを記述できないのはなぜですか(たとえば、
CREATE OR REPLACE PROCEDURE test IS
BEGIN
truncate table table_name; // error
END test;
/
だが、
CREATE OR REPLACE PROCEDURE test IS
BEGIN
execute immediate 'truncate table table_name'; // works fine
END test;
/
なぜ2つ目が正常に実行されたのですか?
ドキュメント にあるように:
PL/SQLプログラム単位内で次のタイプの文を実行できるのは、動的SQLのみです。
- CREATE、DROP、GRANT、REVOKEなどのデータ定義言語(DDL)ステートメント
TRUNCATE
操作はDDL
です。
EXECUTE IMMEDIATE
を使用する場合、実行するDDL
操作は暗黙的に現在のトランザクションをCOMMIT
実行することに注意してください。
PL/SQLコード内のDDLは、実際の必要性よりも例外です。解析は構造検証と見なすことができ、構造が実行時に変更されると失われます。プロシージャは、他のオブジェクト(テーブル、または他のpl/sqlコード、ビューなど)を再度解析することを目的としています。依存オブジェクトが変更されるたびに、再コンパイルする必要があります。したがって、構造の変更以外の解析済みコードを作成することは検証できず、コンパイルもできません。ケースを検討する
DROP TABLE T1;
解析時にテーブルが見つかり、プロシージャが正常にコンパイルされますが、最初の実行時にテーブルが削除され、コードが無効になります(次回DROP TABLEがエラーになる)。同様に、テーブルDDLを変更すると、再コンパイルが必要になるため、コード解析の利点が失われます。