web-dev-qa-db-ja.com

動的SQLのDDL / SCLステートメントでバインド変数を使用できないのはなぜですか?

バインド変数を使用して動的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ステートメントでバインド変数を使用できないのはなぜですか?

14
sampathsris

バインド変数は、DDLステートメントでは許可されていません。したがって、次のステートメントはエラーを引き起こします。

問題

これが発生する理由を理解するには、 動的SQLステートメントの処理方法 を確認する必要があります。

通常、アプリケーションプログラムは、SQLステートメントのテキストとステートメントで使用されるホスト変数の値の入力をユーザーに求めます。次に、OracleはSQLステートメントを解析します。つまり、OracleはSQLステートメントを調べて、構文規則に従っており、有効なデータベースオブジェクトを参照していることを確認します。解析には、データベースのアクセス権の確認も含まれます1、必要なリソースを予約し、最適なアクセスパスを見つけます。

1回答者が強調を追加

解析ステップが発生することに注意してくださいbefore変数を動的ステートメントにバインドします。上記の4つの例を調べると、バインド変数の値を知らなければ、パーサーがこれらの動的SQLステートメントの構文上の有効性を保証する方法がないことがわかります。

  • 例1:パーサーはバインド値が有効かどうかを判断できません。 USING 42の代わりにプログラマーがUSING 'forty-two'を書いた場合はどうなりますか?
  • 例2:パーサーは: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 || '''';
    
24
sampathsris