TOP  >  スタッフブログ  >  技術全般  >  MySQLのストアドプロシージャの使い方 

MySQLのストアドプロシージャの使い方

カテゴリ : 
技術全般
2008-12-3 15:52
satoです。
今回は普段あまり使われないと思うMySQLのストアドプロシージャについて解説したいと思います。

MySQL5.0以降ではストアドプロシージャが使えるようになっています。
通常MySQLでストアドを使うことはないとは思いますが、一連の、CREATE TABLE等とセットでDB処理を書く時などは便利です。

ストアドプロシージャは各RDBMSで独自に実装していることが多いのですが、MySQLは標準SQL準拠で実装されており、それなりに汎用性があるものになっています。とは言っても、PL/SQLとは違うので、どこで汎用的かと言われると難しいです。
PL/SQLとは違いがありますが、大枠としては似ている部分は多いと思います。

■ストアドプロシージャの作成
ストアドプロシージャの作成にはCREATE PROCEDURE命令を使います。
DELIMITER //
CREATE PROCEDURE test_proc(in f int)
BEGIN
  INSERT INTO test_table(val) VALUES(f);
END;
//
DELIMITER ;

DELIMITER命令は、文の区切り文字(デリミタ)を変更します。
わかりづらいのですが、CREATE PROCEDURE命令は、「CREATE PROCEDURE」から「END;//」までが1つの文になり、その中で実行する命令を書くので、例えば、
CREATE PROCEDURE test_proc(in f int)
BEGIN
  INSERT INTO test_table(val) VALUES(f);
END;
;

と、DELIMITER無しにすると、「CREATE PROCEDURE」が「VALUES(f);」で終了してしまい、エラーになってしまいます。これを回避するために一時的にデリミタを//にしています。

これで定義した後に、
CALL test_proc(1);

とすると、INSERT INTOが実行されるのがわかると思います。

■ストアドプロシージャの削除
削除にはDROP PROCEDURE文を使います。DROP TABLE等と同様に、IF EXISTSを付けることができるので、CREATEの前に書いておくと便利かと思われます。

■ストアドファンクション
戻り値が無いものをプロシージャと呼ぶのに対し、戻り値があるものはファンクションと呼びます。
DELIMITER //
CREATE FUNCTION test_func(f int) RETURNS int DETERMINISTIC
BEGIN
  RETURN (f + 2);
END;
//
DELIMITER ;

基本的にはプロシージャと同様ですが、いくつか違う点があります。

・引数にinが不要
プロシージャの引数の先頭のinは、「この値は入力値です」というのを指示するためのもので、プロシージャの場合はoutという指定もできます。これはPHPで言うところのリファレンス渡しに近いものになります。
ファンクションの場合はRETURNで戻り値を指定するので不要です。

・戻り値の型の指定
CREATE FUNCTIONの引数リストの後に、「RETURNS int」というのがあります。ここで戻り値の型を指定します。(この場合はint)

・DETERMINISTIC
これを付けないで定義しようとすると、
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
のようなエラーが発生する場合があります。
入力値が同じ場合に出力値が同じ場合はDETERMINISTIC、そうでない場合はNOT DETERMINISTICを指定します。バイナリログの記録に関わるようです。
SET GLOBAL log_bin_trust_function_creators = 1;
で回避することもできます。

ファンクションはSELECTで呼び出します。
test@localhost[testdb]> select test_func(1);
+--------------+
| test_func(1) |
+--------------+
|            3 |
+--------------+


■変数の定義
DROP FUNCTION IF EXISTS test_func2;
DELIMITER //
CREATE FUNCTION test_func2(f int) RETURNS int DETERMINISTIC
BEGIN
  DECLARE ret int;
  SET ret = f + 2;
  RETURN ret;
END;
//
DELIMITER ;

内部で使う変数の定義にはDECLARE文を使います。
DECLARE文は全てBEGINの直後に書く必要があります。ルーチンの途中に書くことはできません。
...
BEGIN
  DECLARE ret int;
  SET ret = f + 2;
  DECLARE ret2 int;
...

のようなのはエラーになります。
変数に値を代入するにはSET文を使います。

■カーソル
ストアドでよく使う処理として、「SELECTの結果を1行毎に何か処理したい」ということだと思います。PHPのforeach的なものです。
これを実現するにはカーソルというものを使います。
DROP TABLE IF EXISTS test_table;
CREATE TABLE test_table ( a int, b int, c int);
INSERT INTO test_table(a, b, c) VALUES(1, 2, 0);
INSERT INTO test_table(a, b, c) VALUES(2, 3, 0);
INSERT INTO test_table(a, b, c) VALUES(3, 4, 0);

DROP PROCEDURE IF EXISTS test_proc2;

DELIMITER //
CREATE PROCEDURE test_proc2()
BEGIN
    DECLARE eod tinyint;
    DECLARE in_a, in_b int;
    DECLARE out_c int;
    DECLARE cr1 cursor FOR SELECT a, b FROM test_table;
    DECLARE continue handler FOR not found SET eod = 1;
    SET eod = 0;

    OPEN cr1;
    FETCH cr1 INTO in_a, in_b;
    WHILE eod = 0 DO
        SET out_c = in_a * in_b;
        UPDATE test_table SET c = out_c WHERE a = in_a AND b = in_b;

        FETCH cr1 INTO in_a, in_b;
    END WHILE;
    CLOSE cr1;
END
//
DELIMITER ;

カーソルは、SELECTの戻り値のポインタ的なもので、cursor型として定義します。
「DECLARE cr1 cursor FOR」の後に、そのカーソルで呼び出したいSQLを記述します。
「DECLARE continue handler FOR not found SET eod = 1;」は、カーソル呼び出しの際に、データが存在しなくなったら変数eodに1をセットするというhandlerを定義します。これでSELECTが終了したかどうかを判定します。
カーソルのDECLAREは通常変数のDECLAREの後に定義する必要があります。
    DECLARE cr1 cursor FOR SELECT a, b FROM test_table;
    DECLARE out_c int;

のようにしてしまうと、
ERROR 1337 (42000): Variable or condition declaration after cursor or handler declaration

というエラーになります。

後はカーソルをOPENし、FETCHで値を取得するとINTOで指定した変数に代入され、それを処理します。
これを実行すると、

test@localhost[testdb]> SELECT * FROM test_table;
+------+------+------+
| a    | b    | c    |
+------+------+------+
|    1 |    2 |    0 |
|    2 |    3 |    0 |
|    3 |    4 |    0 |
+------+------+------+
3 rows in set (0.01 sec)

test@localhost[testdb]> CALL test_proc2();
Query OK, 1 row affected (0.01 sec)

test@localhost[testdb]> SELECT * FROM test_table;
+------+------+------+
| a    | b    | c    |
+------+------+------+
|    1 |    2 |    2 |
|    2 |    3 |    6 |
|    3 |    4 |   12 |
+------+------+------+
3 rows in set (0.00 sec)

cが反映されているのがわかると思います。


その他、詳しくはMySQLのリファレンスマニュアルを参照してください。

同一カテゴリ(  技術全般 )の最新記事

トラックバック

トラックバックpingアドレス http://ryus.co.jp/modules/d3blog/tb.php/246

コメント

コメントの投稿

コメント投稿に関するルール : コメントに承認は必要ない
検索
XOOPSうさぎ通信
お客様事例
メルマガ登録
メルマガ「XOOPSうさぎ通信」登録

メルマガタグ全一覧

XOOPSうさぎ通信
メールアドレス*必須
お名前*必須
会社名
ひとこと欄
個人情報のお取り扱いについてに同意の上ご登録ください
XOOPSうさぎ通信とは?
事例紹介キーワード
タイムカードと社内ポータルがワンパッケージ!
イントラ+勤怠管理システム イントラタイムカードXOO

XOOPS Cubeサタデーラボ

「知らなかったら損をするCMSを社内で活用する!7つの法則」無料レポート お申し込みフォームはコチラ!
メディア掲載情報
最新スタッフブログ
ブログコメント
ブログカテゴリ
RYUS運営サイト
うさぎにもできるXOOPS Cube入門♪
XOOPS Cube Link
XOOPS Cube Official Web Site
携帯サイト
株式会社RYUS QRコード
株式会社RYUS QRコード
たいせつにしますプライバシー 10823301(01)