バインド変数を使用して動的SQL内でSQLコマンドを実行しようとしています。
-- this procedure is a part of PL/SQL package Test_Pkg
PROCEDURE Set_Nls_Calendar(calendar_ IN VARCHAR2)
IS
BEGIN
EXECUTE IMMEDIATE
'ALTER SESSION
SET NLS_CALENDAR = :cal'
USING IN calendar_;
END Set_Nls_Calendar;
次に、クライアント側で、プロシージャを呼び出そうとしています。
Test_Pkg.Set_Nls_Calendar('Thai Buddha');
しかし、これは私ですORA-02248: invalid option for ALTER SESSION
。
そして私の質問は:動的SQLのDDL/SCLステートメントでバインド変数を使用できないのはなぜですか?
バインド変数は、DDLステートメントでは許可されていません。したがって、次のステートメントはエラーを引き起こします。
例1:DDLステートメント。発生します ORA-01027:バインド変数はデータ定義操作に許可されていません
EXECUTE IMMEDIATE
'CREATE TABLE dummy_table ( dummy_column NUMBER DEFAULT :def_val )'
USING 42;
例2:DDLステートメント。発生します ORA-00904 ::無効な識別子
EXECUTE IMMEDIATE
'CREATE TABLE dummy_table ( :col_name NUMBER )'
USING var_col_name;
例3:SCLステートメント。発生します ORA-02248:ALTER SESSIONのオプションが無効です
EXECUTE IMMEDIATE
'ALTER SESSION SET NLS_CALENDAR = :cal'
USING var_calendar_option;
これが発生する理由を理解するには、 動的SQLステートメントの処理方法 を確認する必要があります。
通常、アプリケーションプログラムは、SQLステートメントのテキストとステートメントで使用されるホスト変数の値の入力をユーザーに求めます。次に、OracleはSQLステートメントを解析します。つまり、OracleはSQLステートメントを調べて、構文規則に従っており、有効なデータベースオブジェクトを参照していることを確認します。解析には、データベースのアクセス権の確認も含まれます1、必要なリソースを予約し、最適なアクセスパスを見つけます。
1回答者が強調を追加
解析ステップが発生することに注意してくださいbefore変数を動的ステートメントにバインドします。上記の4つの例を調べると、バインド変数の値を知らなければ、パーサーがこれらの動的SQLステートメントの構文上の有効性を保証する方法がないことがわかります。
USING 42
の代わりにプログラマーがUSING 'forty-two'
を書いた場合はどうなりますか?:col_name
が有効な列名であるかどうかを判断できません。バインドされた列名が'identifier_that_well_exceeds_thirty_character_identifier_limit'
の場合はどうなりますか?NLS_CALENDAR
の値は定数に組み込まれています(特定のOracleバージョンに対して?)。パーサーは、バインドされた変数が有効な値を持つかどうかを判断できません。したがって、答えは動的SQLのテーブル名や列名などのスキーマ要素をバインドできないということです。また、組み込み定数をバインドすることもできません。
スキーマ要素/定数の参照を動的に実現する唯一の方法は、動的SQLステートメントで文字列連結を使用することです。
例1:
EXECUTE IMMEDIATE
'CREATE TABLE dummy_table ( dummy_column NUMBER DEFAULT ' || to_char(42) || ')';
例2:
EXECUTE IMMEDIATE
'CREATE TABLE dummy_table (' || var_col_name || ' NUMBER )';
例3:
EXECUTE IMMEDIATE
'ALTER SESSION SET NLS_CALENDAR = ''' || var_calendar_option || '''';