Oracleのスクリプト作成について - foolmacky/DevelopDocs GitHub Wiki

■ Oracleのスクリプトのレイヤー

  • わかりにくいのだが、Oracleのスクリプティングには2つのレイヤーがあり、コマンドや変数の扱いが異なっている
  • 一番外側はSQL Plusのスクリプトで、当然ながらSQL Plus上でしか処理できない。
  • その下にPL/SQLのスクリプティングがある。
  • コマンド類や制約が異なっているのは、当然だが、ついつい混乱するのはそれぞれのレイヤーで定義される変数と、スクリプト内での参照の仕方、更新方法だ。
  • コマンドはそれぞれの環境上でしか使えないが、変数については、SQL Plusで定義した変数をPL/SQLでも参照できてしまうのが、混乱の元だ。

■ SQL Plusの変数

  • defineコマンドを使って設定する変数。参照するには変数名に&をつけて使う。単純なスクリプト・ソースの置換機能に過ぎないため、SQLの中で、文字列変数として利用するには参照の前後にクオーテーションをつけなくてはならない。
def table_name=scot
def temp=12
select * from scot where month = '&temp';
select * from &table_name where month = '&temp';
  • 値に再度代入するのもdefineコマンドを使う。
  • この変数はPL/SQLブロックでもそのまま参照することができ、使い方もSQL Plusレイヤーと同じ。ただし、PL/SQLレイヤーでは値を更新することはできない。
  • スクリプトの置換機能に過ぎないため、テーブル名などをこの変数を使って動的に切り替えたりできる。

■ variable変数

  • variableコマンドを使って定義する。型の概念を持つちゃんとした変数。SQL Plusのスクリプト上(PL/SQLのヘッダー部?)で定義し参照もできるが、値の代入はPL/SQLブロック内でのみ可能。
  • なのでSQL Plusスクリプトで代入する場合は、無名ブロックを使って行う。
  • 参照するときは、SQL Plusスクリプト上ではそのまま参照するが、PL/SQLブロックでは「:」をつける必要がある。
def table_name=HOGE
variable v_table_name varchar2(128)

begin
    for i in 0..10 loop
        :v_limit := i;
        @sqls/&table_name
        commit;
    end loop;
    :v_table_name := '&table_name';
    dbms_output.put_line(:v_table_name || ' executed.');
    dbms_output.put_line('&table_name' || ' executed.');
    end;
/

print v_table_name
  • 表現の仕方からしても、SQLのnamed paramと同じメモリ格納をしているのかもしれない。
  • 型が明確なため、テーブル名、カラム名などをこの変数を使って動的に制御することはできない。その場合は一旦文字列としてSQL文を構築し、execute immediateコマンドに与えて実行する。

■ declareセクションで宣言する変数

  • PL/SQLブロック内でのみ使用する変数。declareセクションで型とともに宣言し、続くbeginブロックで使用する。
  • SQL plusスクリプト部からは使うことはできない。最終的なrun(/)コマンドを跨いで使用できるかどうかはわからない。

■ その他注意すべきこと

  • SQL文を別ファイルに保存して、PL/SQLブロック内でそれを「@」コマンドで呼び出して実行する場合、variable変数は「:」をつけて参照する
  • selectするテーブルを変数で切り替えたりする場合は、def変数は直接指定することが可能だが、型を持っているvariable変数はそれはできない。一旦文字列としてSQLを構築してからexecute immediate コマンドで実行する。
  • PL/SQLブロックは実行前に静的にコンパイルされる。その際にif分岐などで、実際には実行されない部分であっても、正しくないSQL(カラムがないなど)が構築される場合は、コンパイルでエラーになってしまう。