7. PL/SQL カーソル

 


📝 PL/SQLカーソル入門:データの流れをコントロールしよう

データベースから大量のデータを取得するとき、どのように処理すればいいのでしょうか?PL/SQLでは、カーソル(Cursor)という仕組みを使って、データの流れを細かくコントロールできます。

例えるなら、カーソルはデータベースの「結果セット」という大きな水の入ったバケツから、一杯ずつ水をすくい上げるための「ひしゃく」のようなものです。


1. カーソルって何? 🪣

カーソルは、SQL文が実行された結果(結果セット)を格納するメモリ領域への「ポインタ」(目印)です。

カーソルの役割:

  • SQL文を実行した結果をメモリに保持する。

  • PL/SQLプログラムで、その結果セットの行に一つずつアクセスして処理できるようにする。

カーソルには、Oracleが自動で扱う「暗黙カーソル」と、私たちが自分で操作する「明示的カーソル」の2種類があります。


2. 暗黙カーソル:おまかせ処理 🤖

INSERT, UPDATE, DELETE, SELECT INTOといったSQL文を実行すると、Oracleが自動的にカーソルを作成してくれます。これが暗黙カーソルです。

私たちはこのカーソルを直接コントロールすることはできませんが、その状態を確認するための4つの属性を使うことができます。

属性名意味
SQL%FOUNDSQL文が1行以上のデータを処理した場合にTRUEを返す。
SQL%NOTFOUNDSQL%FOUNDの逆。データが見つからなかった場合にTRUEを返す。
SQL%ROWCOUNTSQL文によって影響を受けた行の数を返す。
SQL%ISOPENカーソルが開いているかどうか。暗黙カーソルの場合は常にFALSE

【例】%ROWCOUNTを使って更新件数を確認する

SQL
BEGIN
  UPDATE CUSTOMER SET FIRST_NAME = '田中' WHERE CUSTOMER_ID = 16;
  
  -- 更新された行数を表示
  DBMS_OUTPUT.PUT_LINE('更新された行数: ' || SQL%ROWCOUNT);
END;
/

3. 明示的カーソル:自分で操作 ✋

複数の行を細かく処理したい場合は、明示的カーソルを自分で作って操作します。

明示的カーソルを扱う4つのステップ

  1. DECLARE(宣言): カーソルに名前をつけ、どのSQL文を実行するかを定義します。

    • CURSOR カーソル名 IS SELECT文;

  2. OPEN(オープン): カーソルを開き、SQL文を実行して結果セットをメモリに読み込みます。

    • OPEN カーソル名;

  3. FETCH(フェッチ): 結果セットから1行ずつデータを取り出し、PL/SQLの変数に格納します。

    • FETCH カーソル名 INTO 変数;

  4. CLOSE(クローズ): 処理が終わったら、メモリを解放するためにカーソルを閉じます。

    • CLOSE カーソル名;

複数の行を処理する

FETCHは1行ずつしかデータを取れません。複数の行を処理するには、ループ%NOTFOUND属性を組み合わせます。

【構文】

SQL
DECLARE
  CURSOR c IS SELECT * FROM customer WHERE customer_id = 10;
  v_customer_rec c%ROWTYPE; -- レコード変数
BEGIN
  OPEN c;
  LOOP
    FETCH c INTO v_customer_rec;
    EXIT WHEN c%NOTFOUND; -- データがなくなったらループを抜ける
    
    -- ここに1行ごとの処理を書く
    DBMS_OUTPUT.PUT_LINE('名前: ' || v_customer_rec.first_name);
  END LOOP;
  CLOSE c;
END;
/

💡 %ROWTYPEと組み合わせると、複数の変数を宣言する必要がなくなり、コードがとてもシンプルになります。カーソルを使うときは、レコードも一緒に使うのがお勧めです


4. カーソル処理をシンプルに! 🪄

カーソルFORループ

DECLARE, OPEN, FETCH, CLOSEの4つのステップを、たった1つのFORループで自動的に行ってくれる便利な機能です。

【構文】

SQL
BEGIN
  -- カーソルの宣言、オープン、フェッチ、クローズが自動で行われる
  FOR v_rec IN (SELECT * FROM customer WHERE customer_id = 10) LOOP
    -- v_recはレコード変数として自動的に作成される
    DBMS_OUTPUT.PUT_LINE('名前: ' || v_rec.first_name);
  END LOOP;
END;
/

この方法を使えば、コードが驚くほどシンプルになります。特別な理由がない限り、カーソルFORループを使うのがお勧めです。


5. 高度なカーソルテクニック:参照カーソル 🔄

もし、あるプロシージャで取得した結果セットを、別のプロシージャに渡したい場合は、「参照カーソル(Ref Cursor)」を使います。

【構文】

  • SYS_REFCURSORというデータ型でカーソルを宣言します。

  • プロシージャのパラメータとしてSYS_REFCURSORを指定します。

【例】

SQL
CREATE OR REPLACE PROCEDURE show_names (
  p_cursor_in OUT SYS_REFCURSOR -- 結果セットを返す
) AS
BEGIN
  -- カーソルを開き、結果セットをセット
  OPEN p_cursor_in FOR
    SELECT first_name, last_name FROM customer;
END;
/

このようにして、show_namesプロシージャは、customerテーブルのデータを結果セットとして返します。この結果セットは、別のプロシージャやアプリケーションで受け取って処理できます。


6. カーソル処理でよくあるエラー 🚨

カーソルを扱う際には、以下の2つの例外に注意しましょう。

  • CURSOR_ALREADY_OPEN: 開いているカーソルを、再度開こうとしたときに発生。

  • INVALID_CURSOR: カーソルが開かれていないのに、FETCHCLOSEを実行しようとしたときに発生。

これらのエラーを避けるために、IF NOT c%ISOPEN THEN OPEN c;のように、カーソルの状態をチェックしてから操作を行うのが安全です。

前の記事:6. PL/SQL レコード

次の記事:8. PL/SQL コレクション