MySQL 5.0 バージョンからストアドプロシージャをサポートし始めました。
ストアドプロシージャ(Stored Procedure)は、データベース内に複雑なプログラムを格納し、外部プログラムから呼び出せるようにするデータベースオブジェクトです。
ストアドプロシージャは、特定の機能を実現するためのSQL文の集まりであり、コンパイルされてデータベースに作成・保存されます。ユーザーはストアドプロシージャの名前を指定し、必要に応じてパラメータを渡すことで呼び出して実行できます。
ストアドプロシージャは考え方がとてもシンプルで、データベースのSQL言語レベルでのコードのカプセル化と再利用です。
利点
- ストアドプロシージャはカプセル化でき、複雑なビジネスロジックを隠蔽できます。
- ストアドプロシージャは値を返すことができ、パラメータを受け取ることができます。
- ストアドプロシージャはSELECTコマンドで実行できません。なぜなら、それはサブルーチンであり、ビュー、データテーブル、ユーザー定義関数とは異なるからです。
- ストアドプロシージャはデータ検証、ビジネスロジックの強制実行などに使用できます。
欠点
- ストアドプロシージャは、サポートされるプログラミング言語が異なるため、特定のデータベースに特化していることがよくあります。他のベンダーのデータベースシステムに切り替える場合、既存のストアドプロシージャを書き直す必要があります。
- ストアドプロシージャのパフォーマンスチューニングと作成は、各種データベースシステムに制約されます。
一、ストアドプロシージャの作成と呼び出し
- ストアドプロシージャとは、特定の機能を実行するための名前付きのコードブロックです。
- 作成されたストアドプロシージャは、データベースのデータディクショナリに保存されます。
ストアドプロシージャの作成
CREATE
[DEFINER = { user | CURRENT_USER }]
PROCEDURE sp_name ([proc_parameter[,...]])
[characteristic ...] routine_body
proc_parameter:
[ IN | OUT | INOUT ] param_name type
characteristic:
COMMENT 'string'
| LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
routine_body:
Valid SQL routine statement
[begin_label:] BEGIN
[statement_list]
……
END [end_label]
MYSQL ストアドプロシージャの主要な構文
文の終端記号を宣言し、カスタマイズできます:
DELIMITER $$
或
DELIMITER //
ストアドプロシージャを宣言:
CREATE PROCEDURE demo_in_parameter(IN p_in int)
ストアドプロシージャの開始および終了記号:
BEGIN .... END
変数への代入:
SET @p_in=1
変数の定義:
DECLARE l_int int unsigned default 4000000;
mysqlストアドプロシージャ、ストアドファンクションの作成:
create procedure 存储过程名(参数)
ストアドプロシージャ本体:
create function 存储函数名(参数)
例
サンプル操作用にデータベースを作成し、データテーブルをバックアップします:
mysql> create database db1;
mysql> use db1;
mysql> create table PLAYERS as select * from TENNIS.PLAYERS;
mysql> create table MATCHES as select * from TENNIS.MATCHES;
以下はストアドプロシージャの例で、指定された選手が参加したすべての試合を削除します:
mysql> delimiter $$
mysql> CREATE PROCEDURE delete_matches(IN p_playerno INTEGER)
-> BEGIN
-> DELETE FROM MATCHES
-> WHERE playerno = p_playerno;
-> END$$
Query OK, 0 rows affected (0.01 sec)
mysql> delimiter;
解説:デフォルトでは、ストアドプロシージャはデフォルトデータベースに関連付けられます。特定のデータベースの下にストアドプロシージャを作成したい場合は、プロシージャ名の前にデータベース名をプレフィックスとして付けます。プロシージャを定義するときに、使用しますDELIMITER $$コマンドで文の終端記号をセミコロンから;一時的に2つに変更して$$、プロシージャ本体で使用されるセミコロンがクライアント(mysqlなど)によって解釈されずに直接サーバーに渡されるようにします。
ストアドプロシージャの呼び出し:
call sp_name[(传参)];
mysql> select * from MATCHES;
+---------+--------+----------+-----+------+
| MATCHNO | TEAMNO | PLAYERNO | WON | LOST |
+---------+--------+----------+-----+------+
| 1 | 1 | 6 | 3 | 1 |
| 7 | 1 | 57 | 3 | 0 |
| 8 | 1 | 8 | 0 | 3 |
| 9 | 2 | 27 | 3 | 2 |
| 11 | 2 | 112 | 2 | 3 |
+---------+--------+----------+-----+------+
5 rows in set (0.00 sec)
mysql> call delete_matches(57);
Query OK, 1 row affected (0.03 sec)
mysql> select * from MATCHES;
+---------+--------+----------+-----+------+
| MATCHNO | TEAMNO | PLAYERNO | WON | LOST |
+---------+--------+----------+-----+------+
| 1 | 1 | 6 | 3 | 1 |
| 8 | 1 | 8 | 0 | 3 |
| 9 | 2 | 27 | 3 | 2 |
| 11 | 2 | 112 | 2 | 3 |
+---------+--------+----------+-----+------+
4 rows in set (0.00 sec)
解説:ストアドプロシージャ内でパラメータを渡す変数p_playernoが設定されています。ストアドプロシージャを呼び出すとき、パラメータを渡すことで57をp_playernoに代入し、その後ストアドプロシージャ内のSQL操作を実行します。
ストアドプロシージャ本体
- ストアドプロシージャ本体には、プロシージャ呼び出し時に実行する必要がある文が含まれます。例:DML、DDL文、if-then-elseやwhile-do文、変数を宣言するdeclare文など。
- プロシージャ本体の形式:beginで始まり、endで終わります(ネスト可能)。
BEGIN
BEGIN
BEGIN
statements;
END
END
END
注意:各ネストブロックおよびその中の各文はセミコロンで終了する必要がありますが、プロシージャ本体の終了を示すbegin-endブロック(複合文compound statementとも呼ばれる)にはセミコロンは不要です。
文ブロックにラベルを付ける:
[begin_label:] BEGIN
[statement_list]
END [end_label]
例:
label1: BEGIN
label2: BEGIN
label3: BEGIN
statements;
END label3 ;
END label2;
END label1
ラベルには2つの役割があります:
- 1、コードの可読性を高める
- 2、一部の文(例:leave文やiterate文)ではラベルが必要です。
二、ストアドプロシージャのパラメータ
MySQLストアドプロシージャのパラメータはストアドプロシージャの定義で使用され、IN、OUT、INOUTの3種類のパラメータタイプがあります。形式は次のとおりです:
CREATEPROCEDURE 存储过程名([[IN |OUT |INOUT ] 参数名 数据类形...])
- IN 入力パラメータ:呼び出し元がプロシージャに値を渡すことを示します(渡す値はリテラルまたは変数にできます)。
- OUT 出力パラメータ:プロシージャが呼び出し元に値を渡すことを示します(複数の値を返すことができます)(渡す値は変数のみです)。
- INOUT 入出力パラメータ:呼び出し元がプロシージャに値を渡すと同時に、プロシージャが呼び出し元に値を渡すことを示します(値は変数のみです)。
1、in 入力パラメータ
mysql> delimiter $$
mysql> create procedure in_param(in p_in int)
-> begin
-> select p_in;
-> set p_in=2;
-> select P_in;
-> end$$
mysql> delimiter ;
mysql> set @p_in=1;
mysql> call in_param(@p_in);
+------+
| p_in |
+------+
| 1 |
+------+
+------+
| P_in |
+------+
| 2 |
+------+
mysql> select @p_in;
+-------+
| @p_in |
+-------+
| 1 |
+-------+
以上からわかるように、p_in はストアドプロシージャ内で変更されますが、影響しません@p_inの値には影響しません。なぜなら前者はローカル変数、後者はグローバル変数だからです。
2、out出力パラメータ
mysql> delimiter //
mysql> create procedure out_param(out p_out int)
-> begin
-> select p_out;
-> set p_out=2;
-> select p_out;
-> end
-> //
mysql> delimiter ;
mysql> set @p_out=1;
mysql> call out_param(@p_out);
+-------+
| p_out |
+-------+
| NULL |
+-------+
+-------+
| p_out |
+-------+
| 2 |
+-------+
mysql> select @p_out;
+--------+
| @p_out |
+--------+
| 2 |
+--------+
3、inout入出力パラメータ
mysql> delimiter $$
mysql> create procedure inout_param(inout p_inout int)
-> begin
-> select p_inout;
-> set p_inout=2;
-> select p_inout;
-> end
-> $$
mysql> delimiter ;
mysql> set @p_inout=1;
mysql> call inout_param(@p_inout);
+---------+
| p_inout |
+---------+
| 1 |
+---------+
+---------+
| p_inout |
+---------+
| 2 |
+---------+
mysql> select @p_inout;
+----------+
| @p_inout |
+----------+
| 2 |
+----------+
注意:
1、プロシージャにパラメータがない場合でも、プロシージャ名の後に括弧を書く必要があります。例:
CREATE PROCEDURE sp_name ([proc_parameter[,...]]) ……
2、パラメータ名が列名と同じにならないようにしてください。そうしないと、プロシージャ本体内でパラメータ名が列名として扱われます。
提案:
- 入力値にはinパラメータを使用します。
- 戻り値にはoutパラメータを使用します。
- inoutパラメータはできるだけ使用を避けます。
三、変数
1. 変数の定義
ローカル変数の宣言は必ずストアドプロシージャ本体の先頭に置く必要があります:
DECLAREvariable_name [,variable_name...] datatype [DEFAULT value];
ここで、datatype は MySQL のデータ型です。例:int, float, date, varchar(length)
例:
DECLARE l_int int unsigned default 4000000;
DECLARE l_numeric number(8,2) DEFAULT 9.95;
DECLARE l_date date DEFAULT '1999-12-31';
DECLARE l_datetime datetime DEFAULT '1999-12-31 23:59:59';
DECLARE l_varchar varchar(255) DEFAULT 'This will not be padded';
2. 変数への代入
SET 变量名 = 表达式值 [,variable_name = expression ...]
3. ユーザー変数
MySQLクライアントでユーザー変数を使用する:
mysql > SELECT 'Hello World' into @x;
mysql > SELECT @x;
+-------------+
| @x |
+-------------+
| Hello World |
+-------------+
mysql > SET @y='Goodbye Cruel World';
mysql > SELECT @y;
+---------------------+
| @y |
+---------------------+
| Goodbye Cruel World |
+---------------------+
mysql > SET @z=1+2+3;
mysql > SELECT @z;
+------+
| @z |
+------+
| 6 |
+------+
ストアドプロシージャ内でユーザー変数を使用する
mysql > CREATE PROCEDURE GreetWorld( ) SELECT CONCAT(@greeting,' World');
mysql > SET @greeting='Hello';
mysql > CALL GreetWorld( );
+----------------------------+
| CONCAT(@greeting,' World') |
+----------------------------+
| Hello World |
+----------------------------+
ストアドプロシージャ間でグローバルスコープのユーザー変数を渡す
mysql> CREATE PROCEDURE p1() SET @last_procedure='p1';
mysql> CREATE PROCEDURE p2() SELECT CONCAT('Last procedure was ',@last_procedure);
mysql> CALL p1( );
mysql> CALL p2( );
+-----------------------------------------------+
| CONCAT('Last procedure was ',@last_proc |
+-----------------------------------------------+
| Last procedure was p1 |
+-----------------------------------------------+
注意:
- 1、ユーザー変数名は通常@で始まります
- 2、ユーザー変数を乱用すると、プログラムが理解・管理しにくくなります
四、コメント
MySQL ストアドプロシージャでは2種類のスタイルのコメントを使用できます
2つのハイフン--:このスタイルは通常、単行コメントに使用されます。
c スタイル:通常、複数行コメントに使用されます。
例:
mysql > DELIMITER //
mysql > CREATE PROCEDURE proc1 --nameストアドプロシージャ名
->(IN parameter1 INTEGER)
-> BEGIN
-> DECLARE variable1 CHAR(10);
-> IF parameter1 = 17 THEN
-> SET variable1 = 'birds';
-> ELSE
-> SET variable1 = 'beasts';
-> END IF;
-> INSERT INTO table1 VALUES (variable1);
-> END
-> //
mysql > DELIMITER ;
MySQLストアドプロシージャの呼び出し
callとプロシージャ名、および括弧を使用します。括弧内には必要に応じてパラメータを追加します。パラメータには入力パラメータ、出力パラメータ、入出力パラメータが含まれます。具体的な呼び出し方法は上記の例を参照してください。
MySQLストアドプロシージャのクエリ
データベース内にどのようなテーブルがあるかを知りたい場合、通常は次を使用しますshowtables;で確認します。では、特定のデータベースの下にあるストアドプロシージャを確認する場合も同じ方法が使えるでしょうか?答えは、特定のデータベースの下にあるストアドプロシージャを確認できますが、別の方法です。
次の文でクエリを実行できます:
selectname from mysql.proc where db='数据库名';
或者
selectroutine_name from information_schema.routines where routine_schema='数据库名';
或者
showprocedure status where db='数据库名';
特定のストアドプロシージャの詳細を知りたい場合は、どうすればよいでしょうか?テーブルと同じようにdescribe テーブル名で確認できるのでしょうか?
答えは:ストアドプロシージャの詳細を確認できますが、別の方法を使用する必要があります:
SHOW CREATE PROCEDURE 数据库.存储过程名;
これで現在のストアドプロシージャの詳細を確認できます。
MySQLストアドプロシージャの変更
ALTER PROCEDURE
CREATE PROCEDURE で作成された事前に指定されたストアドプロシージャを変更しても、関連するストアドプロシージャやストアドファンクションには影響しません。
MySQLストアドプロシージャの削除
ストアドプロシージャの削除は比較的簡単で、テーブルの削除と同じです:
DROPPROCEDURE
MySQL から1つまたは複数のストアドプロシージャを削除します。
MySQLストアドプロシージャの制御文
(1). 変数のスコープ
内部の変数はそのスコープ内でより高い優先度を持ちます。end に到達すると、内部変数は消滅し、その時点でスコープ外になるため、変数はもはや見えなくなります。なぜなら、ストアドプロシージャの外ではこの宣言された変数を見つけることができないからです。ただし、outパラメータを使用するか、その値をセッション変数に割り当てることで値を保存できます。
mysql > DELIMITER //
mysql > CREATE PROCEDURE proc3()
-> begin
-> declare x1 varchar(5) default 'outer';
-> begin
-> declare x1 varchar(5) default 'inner';
-> select x1;
-> end;
-> select x1;
-> end;
-> //
mysql > DELIMITER ;
(2). 条件文
1. if-then-else 文
mysql > DELIMITER //
mysql > CREATE PROCEDURE proc2(IN parameter int)
-> begin
-> declare var int;
-> set var=parameter+1;
-> if var=0 then
-> insert into t values(17);
-> end if;
-> if parameter=0 then
-> update t set s1=s1+1;
-> else
-> update t set s1=s1+2;
-> end if;
-> end;
-> //
mysql > DELIMITER ;
2. case文:
mysql > DELIMITER //
mysql > CREATE PROCEDURE proc3 (in parameter int)
-> begin
-> declare var int;
-> set var=parameter+1;
-> case var
-> when 0 then
-> insert into t values(17);
-> when 1 then
-> insert into t values(18);
-> else
-> insert into t values(19);
-> end case;
-> end;
-> //
mysql > DELIMITER ;
case
when var=0 then
insert into t values(30);
when var>0 then
when var<0 then
else
end case
(3). ループ文
1. while ···· end while
mysql > DELIMITER //
mysql > CREATE PROCEDURE proc4()
-> begin
-> declare var int;
-> set var=0;
-> while var<6 do
-> insert into t values(var);
-> set var=var+1;
-> end while;
-> end;
-> //
mysql > DELIMITER ;
while 条件 do
--循环体
endwhile
2. repeat···· end repeat
それは操作を実行した後に結果をチェックし、while は実行前にチェックします。
mysql > DELIMITER //
mysql > CREATE PROCEDURE proc5 ()
-> begin
-> declare v int;
-> set v=0;
-> repeat
-> insert into t values(v);
-> set v=v+1;
-> until v>=5
-> end repeat;
-> end;
-> //
mysql > DELIMITER ;
repeat
--循环体
until 循环条件
end repeat;
3. loop ·····endloop
loop ループは初期条件を必要としません。この点は while ループと似ています。また、repeat ループと同様に終了条件も必要としません。leave 文はループを離れることを意味します。
mysql > DELIMITER //
mysql > CREATE PROCEDURE proc6 ()
-> begin
-> declare v int;
-> set v=0;
-> LOOP_LABLE:loop
-> insert into t values(v);
-> set v=v+1;
-> if v >=5 then
-> leave LOOP_LABLE;
-> end if;
-> end loop;
-> end;
-> //
mysql > DELIMITER ;
4. LABLES ラベル:
ラベルは begin、repeat、while、または loop 文の前に使用できます。文ラベルは正しい文の前にのみ使用できます。ループを抜け出して、実行命令を複合文の最後のステップに到達させることができます。
(4). ITERATE 反復
ITERATE は複合文のラベルを参照して、複合文を再開します。
mysql > DELIMITER //
mysql > CREATE PROCEDURE proc10 ()
-> begin
-> declare v int;
-> set v=0;
-> LOOP_LABLE:loop
-> if v=3 then
-> set v=v+1;
-> ITERATE LOOP_LABLE;
-> end if;
-> insert into t values(v);
-> set v=v+1;
-> if v>=5 then
-> leave LOOP_LABLE;
-> end if;
-> end loop;
-> end;
-> //
mysql > DELIMITER ;
参考記事:
https://www.cnblogs.com/geaozhang/p/6797357.html
http://blog.sina.com.cn/s/blog_86fe5b440100wdyt.html