定义
- 存储在数据库端的一组 SQL 语句集。
 - 用户可以通过存储过程名和传参多次调用的程序模块。
 - 存储过程的特点:  
- 使用灵活,可以使用流控语句、自定义变量等完成复杂的业务逻辑。
 - 提高数据安全性,屏蔽应用程序直接对表的操作,易于进行审计。
 - 减少网络传输。
 - 提高代码维护的复杂度,实际使用需要结合业务评估。
 
 
语法
CREATE[DEFINER = { user | CURRENT_USER }]PROCEDURE sp_name ([proc_parameter[,...]])[characteristic ...] routine_bodyproc_parameter:[ IN | OUT | INOUT ] param_name typecharacteristic: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-- 删除DROP PROCEDURE procedure_name;
:::warning 注意:只有 PROCEDURE 才有 IN(传入)、OUT(传出)、INOUT(传入传出)参数,自定义函数(只有)默认就是 IN。 :::
流程控制语句
官方文档:https://dev.mysql.com/doc/refman/5.7/en/flow-control-statements.html
---- IF---- 语法IF search_condition THEN statement_list[ELSEIF search_condition THEN statement_list] ...[ELSE statement_list]END IF-- 例子mysql> delimiter //mysql> create procedure pcd_test_1 (in param_a int) -- 创建一个-> begin-> declare a int; -- delcare声明了该变量的作用域在该procedure中-> if param_a > 10 then set a:=11;-> elseif param_a = 10 then set a:=10;-> else set a:=9;-> end if;-> end;//Query OK, 0 rows affected (0.01 sec)mysql> select @a; -- 查看当前会话中变量a的值+------+| @a |+------+| NULL | -- 当前会话中a为NULL+------+1 row in set (0.00 sec)mysql> call pcd_test_1(1);+------+| a |+------+| 9 |+------+1 row in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)mysql> call pcd_test_1(10);+------+| a |+------+| 10 |+------+1 row in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)mysql> call pcd_test_1(20);+------+| a |+------+| 11 |+------+1 row in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)mysql> select @a;+------+| @a |+------+| NULL | -- 使用了declare,使得procedure中a的作用域限制在了procedure内+------+1 row in set (0.00 sec)---- CASE WHEN---- CASE WHEN 语法CASE case_valueWHEN when_value THEN statement_list[WHEN when_value THEN statement_list] ...[ELSE statement_list]END CASE-- 或者是CASEWHEN search_condition THEN statement_list[WHEN search_condition THEN statement_list] ...[ELSE statement_list]END CASE---- CASE WHEN 例子--mysql> delimiter //mysql>mysql> create procedure pcd_test_2(in param_1 int)-> begin-> case param_1-- 当case后面有value时,该value会和when中的when_value进行"="判断-- 相等则执行then后面的语句,然后跳出;否则就进行下一次when的匹配-> when 2 then select 200;-> when 3 then select 300;-> else-> begin-- 当没有匹配时,且else中没有要执行的语句-- 则给一个begin/end的空语句;-- 或者不写else语句;-> end;-> end case;-> end;//Query OK, 0 rows affected (0.03 sec)mysql> delimiter ;mysql> call pcd_test_2(1);Query OK, 0 rows affected (0.00 sec)mysql> call pcd_test_2(2);+-----+| 200 |+-----+| 200 |+-----+1 row in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)mysql> call pcd_test_2(3);+-----+| 300 |+-----+| 300 |+-----+1 row in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)-- 另外一种SQL语法请参考rank排名作业;注意when后跟的是condition---- WHILE 循环---- WHILE 语法[begin_label:] WHILE search_condition DOstatement_listEND WHILE [end_label]-- WHILE举例mysql> delimiter //mysql>mysql> create procedure pcd_test_3(in param_1 int)-> begin-> declare a int default 1;-> while param_1 > 10 do-> set param_1 = param_1 - 1;-> set a = a + 1;-> end while;-> select a;-> end;//Query OK, 0 rows affected (0.01 sec)mysql> delimiter ;mysql> call pcd_test_3(15); -- 15 - 10 = 5;需要5次循环+------+| a |+------+| 6 | -- a + 5 = 6+------+1 row in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)---- REPEAT 循环---- REPEAT 语法[begin_label:] REPEATstatement_listUNTIL search_conditionEND REPEAT [end_label]mysql> delimiter //mysql> create procedure pcd_test_4(in param_1 int)-> begin-> SET @x = 0; -- 没有使用declare,所以x是会话级别的-> REPEAT-> SET @x = @x + 1;-> UNTIL @x > param_1 END REPEAT;-> end;//Query OK, 0 rows affected (0.01 sec)mysql> delimiter ;mysql> call pcd_test_4(10);Query OK, 0 rows affected (0.00 sec)mysql> select @x; -- x是会话级别的+------+| @x |+------+| 11 | -- 一共循环11次(10>10 为False,11 > 10为True,才跳出)+------+1 row in set (0.00 sec)---- loop 循环---- loop语法[begin_label:] LOOPstatement_listEND LOOP [end_label]-- ITERATE 和label相结合,表示继续从label处执行-- LEAVE 和label相结合,表示从label 标记的代码段离开-- loop 例子mysql> delimiter //mysql> create procedure pcd_test_5(in param_1 int)-> begin-> test_label: loop-> set param_1 := param_1 + 1; -- 参数累加-> if param_1 < 10 then -- 如果累加的值小于10-> iterate test_label; -- 继续执行 标签 test_label-> end if;-> leave test_label; -- 如果>=10则离开这个test_label(loop)-> end loop test_label;-> set @x = param_1; -- 设置会话级别的变量-> end;//Query OK, 0 rows affected (0.02 sec)mysql> delimiter ;mysql> call pcd_test_5(5); -- 5<10 ,累加5次后>=10为true,离开循环Query OK, 0 rows affected (0.00 sec)mysql> select @x;+------+| @x |+------+| 10 | -- 累加到10的 param_1 赋值给 x, 即为10+------+1 row in set (0.00 sec)-- 老师给出的例子, 阶乘mysql> create table test_proc_1(a int, b int); -- 给一个存放数据的表Query OK, 0 rows affected (0.15 sec)mysql> delimiter //mysql> create procedure proc_test1(in total int, out res int)-> begin-> declare i int;-> set i := 1;-> set res := 1;-> if total <= 0 then-> set total := 1;-> end if;-> while i <= total do-> set res := res * i;-> insert into test_proc_1 values(i, res);-> set i := i + 1;-> end while;-> end;//Query OK, 0 rows affected (0.01 sec)mysql> delimiter ;mysql> set @res_value := 0;Query OK, 0 rows affected (0.00 sec)mysql> call proc_test1(5, @res_value); -- 因为res是out变量,要预先有这个变量,这里上面设置了res_value(实参和形参不必同名)Query OK, 1 row affected (0.15 sec)mysql> select @res_value;+------------+| @res_value |+------------+| 120 | -- 5的阶乘的结果是120+------------+1 row in set (0.00 sec)mysql> select * from test_proc_1;+------+------+| a | b |+------+------+| 1 | 1 || 2 | 2 || 3 | 6 || 4 | 24 || 5 | 120 | -- 每次insert的结果+------+------+5 rows in set (0.00 sec)
作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/wgmill 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
