PL/SQL使ったからメモしておく

📅 March 14, 2022

⏱️3 min read

無名ブロック

SQLPlusやSQLDeveloperなどのツールで実行する、PL/SQLブロックのこと。

DECLARE
  /* 宣言セクション */
BEGIN
  /* 実行可能セクション */
EXCEPTION
  /* 例外セクション */
END;

構成

宣言セクション、実行可能セクション、例外処理セクションの3つのセクションから構成され、実行可能セクションのみ必須。

宣言セクション(DECLARE)
変数や定数、カーソルや関数、例外などを宣言を記述するセクション。宣言する必要がなければDECLAREは省略可能。

実行可能セクション(BEGIN)
SQL文や制御ロジックなどの実行文を記述するセクション。ここは必須。

例外セクション(EXCEPTION)
実行可能セクションで発生した例外をキャッチし、対応処置を記述するセクション。例外を捕捉する必要がなければEXCEPTIONは省略可能。

終わり(END)
PL/SQLブロックの最後に必ず記述。

CURSOR

データの「検索条件」と「現在位置」を保持して、複数の検索結果を1件ずつ処理するための仕組み。宣言部で宣言する必要がある。 データ型の代わりに検索条件(SELECT文)を指定する。

カーソルの宣言と併せて、カーソルの1行分のデータを代入する変数を宣言する。( {変数名}%ROWTYPE
OPEN {カーソル名}; で、カーソルに紐づいたSELECT文を実行して、カーソルに結果セットを保持。
FETCH {カーソル名} INTO {変数名}; で、カーソルの結果セットから1行読み込んで変数に代入。
EXIT WHEN {終了条件}; は、ループ処理の終了条件。

カーソルの引数を設定することも可能。OPEN時に引数を渡すことで動的なSQLにできる。

CURSORを使ってUPDATE

CURSORを定義する際に FOR UPDATE をつけることで、 CURRENT OF {カーソル名} を使って楽に更新できる。

OPEN cursorName;
FOR i IN 1..10 LOOP
    FETCH cursorName INTO val;
    UPDATE
        SAMPLE_TABLE
    SET
        SAMPLE_R = '更新値'
    WHERE
        CURRENT OF cursorName;

END LOOP;
CLOSE cursorName;

パフォーマンス関連

レコードの大量更新はバルクアップデートを使う

PL/SQLでは、内部的にはSQLエンジンとPL/SQLエンジンの2つのエンジンが、それぞれSQL文とPL/SQL文の処理を担当して実行する。

例えばループ内でインサートをしていると、ループの回数分エンジンの切替が発生していることになる。これは、コンテキスト・スイッチと呼ばれ、その都度オーバーヘッドが発生して、パフォーマンスが低下することになる。

FORALL文を指定して実行してバルク処理を行うことで、エンジンの切り替えを最小限に抑え、パフォーマンス向上を狙うといい。

やり方は検索。