MySQL
 Computer >> コンピューター >  >> プログラミング >> MySQL

MySQLストアドプロシージャ内で結果セットを処理する方法(カーソルの使い方)

MySQLのストアドプロシージャ内でクエリが返す結果セットを1行ずつ処理したい場合には、カーソル(CURSOR)を使用します。カーソルを使うことで、SELECT文が返した複数行を順番に取り出し、各行に対して個別の処理を行うことができます。

カーソルとは

カーソルは、結果セット上を「指し示しながら」1行ずつ移動してデータを読み取るための仕組みです。一般的な処理の流れは以下の通りです。

  • DECLARE:カーソルを宣言し、対応付けるSELECT文を定義する
  • OPEN:カーソルを開き、結果セットを取得する
  • FETCH:現在の行の値を変数に取り込み、次の行へ進む
  • CLOSE:すべての行を処理した後、カーソルを閉じる

サンプルテーブルの準備

ここでは、次のような「student_info」テーブルを例に説明します。

mysql> Select * from student_info;
+-----+---------+----------+------------+
| id  | Name    | Address  | Subject    |
+-----+---------+----------+------------+
| 101 | YashPal | Amritsar | History    |
| 105 | Gaurav  | Jaipur   | Literature |
| 125 | Raman   | Shimla   | Computers  |
+-----+---------+----------+------------+
3 rows in set (0.00 sec)

カーソルを使ったストアドプロシージャの作成

次の例では、テーブルに登録されているすべての住所(Address)を取り出し、「;」(セミコロン)区切りの文字列として連結して返すプロシージャ「list_address」を作成します。

mysql> Delimiter //
mysql> CREATE PROCEDURE list_address (INOUT address_list varchar(255))
    -> BEGIN
    -> DECLARE value_finished INTEGER DEFAULT 0;
    -> DECLARE value_address varchar(100) DEFAULT "";
    -> DEClARE address_cursor CURSOR FOR
    -> SELECT address FROM student_info;
    -> DECLARE CONTINUE HANDLER
    -> FOR NOT FOUND SET value_finished = 1;
    -> OPEN address_cursor;
    -> get_address: LOOP
    -> FETCH address_cursor INTO value_address;
    -> IF value_finished = 1 THEN
    -> LEAVE get_address;
    -> END IF;
    -> SET address_list = CONCAT(value_address,";",address_list);
    -> END LOOP get_address;
    -> CLOSE address_cursor;
    -> END //
Query OK, 0 rows affected (0.00 sec)

処理内容のポイント

  • DECLARE value_finished INTEGER DEFAULT 0; … 全行の読み取りが完了したかどうかを判定するためのフラグ変数です。
  • DECLARE address_cursor CURSOR FOR SELECT address FROM student_info; … student_infoテーブルから住所を取得するカーソルを宣言しています。
  • DECLARE CONTINUE HANDLER FOR NOT FOUND SET value_finished = 1; … FETCHで読み取る行がなくなったとき(NOT FOUND)にフラグを立てるハンドラです。これによりループを安全に終了できます。
  • SET address_list = CONCAT(value_address,";",address_list); … 取り出した住所を既存の文字列の先頭に連結していきます。

プロシージャの実行と結果確認

作成したプロシージャを呼び出して、結果を確認してみましょう。まずデリミタを元に戻し、ユーザー定義変数を初期化してからCALL文で実行します。

mysql> DELIMITER ;

mysql> Set @address_list = "";
Query OK, 0 rows affected (0.00 sec)

mysql> CALL list_address(@address_list);
Query OK, 0 rows affected (0.00 sec)

mysql> Select @address_list;
+-------------------------+
| @address_list           |
+-------------------------+
| Shimla;Jaipur;Amritsar; |
+-------------------------+
1 row in set (0.00 sec)

このように、カーソルを使うことでストアドプロシージャ内でも結果セットの各行を柔軟に処理できることが分かります。なお、大量の行を扱う場合はパフォーマンスへの影響も考慮し、可能であればGROUP_CONCAT関数など集合操作での代替も検討するとよいでしょう。

  1. MySQLストアドプロシージャでFORループを実現する方法【LOOP文の使い方を解説】

    MySQLのストアドプロシージャには、他のプログラミング言語のような「FOR LOOP」構文は標準では用意されていません。しかし、LOOP文とLEAVE、ITERATEを組み合わせることで、FORループと同じ動作を実現できます。基本構文以下は、MySQLストアドプロシージャでFORループのように動作させるための基本的な構文です。delimiter //CREATE procedure yourProcedureName()wholeblock:BEGIN   DECLARE anyVariableName1 INT;   DECLAR

  2. MySQLストアドプロシージャで条件分岐を設定する方法(IF...ELSE構文の使い方)

    MySQLのストアドプロシージャ内で条件分岐を実装したい場合は、IF...ELSE構文を使用します。この構文を使うことで、条件に応じて異なる処理を実行できるようになります。IF...ELSE構文の基本形MySQLにおけるIF...ELSE文の基本的な書式は以下のとおりです。IF yourCondition THEN    yourStatement1;ELSE    yourStatement2;END IF;yourCondition:評価される条件式(例:変数が10より大きいかどうか)yourStatement