定义

  • 存储在数据库端的一组 SQL 语句集。
  • 用户可以通过存储过程名和传参多次调用的程序模块。
  • 存储过程的特点:
    • 使用灵活,可以使用流控语句、自定义变量等完成复杂的业务逻辑。
    • 提高数据安全性,屏蔽应用程序直接对表的操作,易于进行审计。
    • 减少网络传输。
    • 提高代码维护的复杂度,实际使用需要结合业务评估。

语法

  1. CREATE
  2. [DEFINER = { user | CURRENT_USER }]
  3. PROCEDURE sp_name ([proc_parameter[,...]])
  4. [characteristic ...] routine_body
  5. proc_parameter:
  6. [ IN | OUT | INOUT ] param_name type
  7. characteristic:
  8. COMMENT 'string'
  9. | LANGUAGE SQL
  10. | [NOT] DETERMINISTIC
  11. | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  12. | SQL SECURITY { DEFINER | INVOKER }
  13. routine_body:
  14. Valid SQL routine statement
  15. -- 删除
  16. DROP PROCEDURE procedure_name;

:::warning 注意:只有 PROCEDURE 才有 IN(传入)、OUT(传出)、INOUT(传入传出)参数,自定义函数(只有)默认就是 IN。 :::

流程控制语句

官方文档:https://dev.mysql.com/doc/refman/5.7/en/flow-control-statements.html

  1. --
  2. -- IF
  3. --
  4. -- 语法
  5. IF search_condition THEN statement_list
  6. [ELSEIF search_condition THEN statement_list] ...
  7. [ELSE statement_list]
  8. END IF
  9. -- 例子
  10. mysql> delimiter //
  11. mysql> create procedure pcd_test_1 (in param_a int) -- 创建一个
  12. -> begin
  13. -> declare a int; -- delcare声明了该变量的作用域在该procedure
  14. -> if param_a > 10 then set a:=11;
  15. -> elseif param_a = 10 then set a:=10;
  16. -> else set a:=9;
  17. -> end if;
  18. -> end;//
  19. Query OK, 0 rows affected (0.01 sec)
  20. mysql> select @a; -- 查看当前会话中变量a的值
  21. +------+
  22. | @a |
  23. +------+
  24. | NULL | -- 当前会话中aNULL
  25. +------+
  26. 1 row in set (0.00 sec)
  27. mysql> call pcd_test_1(1);
  28. +------+
  29. | a |
  30. +------+
  31. | 9 |
  32. +------+
  33. 1 row in set (0.00 sec)
  34. Query OK, 0 rows affected (0.00 sec)
  35. mysql> call pcd_test_1(10);
  36. +------+
  37. | a |
  38. +------+
  39. | 10 |
  40. +------+
  41. 1 row in set (0.00 sec)
  42. Query OK, 0 rows affected (0.00 sec)
  43. mysql> call pcd_test_1(20);
  44. +------+
  45. | a |
  46. +------+
  47. | 11 |
  48. +------+
  49. 1 row in set (0.00 sec)
  50. Query OK, 0 rows affected (0.00 sec)
  51. mysql> select @a;
  52. +------+
  53. | @a |
  54. +------+
  55. | NULL | -- 使用了declare,使得procedurea的作用域限制在了procedure
  56. +------+
  57. 1 row in set (0.00 sec)
  58. --
  59. -- CASE WHEN
  60. --
  61. -- CASE WHEN 语法
  62. CASE case_value
  63. WHEN when_value THEN statement_list
  64. [WHEN when_value THEN statement_list] ...
  65. [ELSE statement_list]
  66. END CASE
  67. -- 或者是
  68. CASE
  69. WHEN search_condition THEN statement_list
  70. [WHEN search_condition THEN statement_list] ...
  71. [ELSE statement_list]
  72. END CASE
  73. --
  74. -- CASE WHEN 例子
  75. --
  76. mysql> delimiter //
  77. mysql>
  78. mysql> create procedure pcd_test_2(in param_1 int)
  79. -> begin
  80. -> case param_1
  81. -- case后面有value时,该value会和when中的when_value进行"="判断
  82. -- 相等则执行then后面的语句,然后跳出;否则就进行下一次when的匹配
  83. -> when 2 then select 200;
  84. -> when 3 then select 300;
  85. -> else
  86. -> begin
  87. -- 当没有匹配时,且else中没有要执行的语句
  88. -- 则给一个begin/end的空语句;
  89. -- 或者不写else语句;
  90. -> end;
  91. -> end case;
  92. -> end;//
  93. Query OK, 0 rows affected (0.03 sec)
  94. mysql> delimiter ;
  95. mysql> call pcd_test_2(1);
  96. Query OK, 0 rows affected (0.00 sec)
  97. mysql> call pcd_test_2(2);
  98. +-----+
  99. | 200 |
  100. +-----+
  101. | 200 |
  102. +-----+
  103. 1 row in set (0.00 sec)
  104. Query OK, 0 rows affected (0.00 sec)
  105. mysql> call pcd_test_2(3);
  106. +-----+
  107. | 300 |
  108. +-----+
  109. | 300 |
  110. +-----+
  111. 1 row in set (0.00 sec)
  112. Query OK, 0 rows affected (0.00 sec)
  113. -- 另外一种SQL语法请参考rank排名作业;注意when后跟的是condition
  114. --
  115. -- WHILE 循环
  116. --
  117. -- WHILE 语法
  118. [begin_label:] WHILE search_condition DO
  119. statement_list
  120. END WHILE [end_label]
  121. -- WHILE举例
  122. mysql> delimiter //
  123. mysql>
  124. mysql> create procedure pcd_test_3(in param_1 int)
  125. -> begin
  126. -> declare a int default 1;
  127. -> while param_1 > 10 do
  128. -> set param_1 = param_1 - 1;
  129. -> set a = a + 1;
  130. -> end while;
  131. -> select a;
  132. -> end;//
  133. Query OK, 0 rows affected (0.01 sec)
  134. mysql> delimiter ;
  135. mysql> call pcd_test_3(15); -- 15 - 10 = 5;需要5次循环
  136. +------+
  137. | a |
  138. +------+
  139. | 6 | -- a + 5 = 6
  140. +------+
  141. 1 row in set (0.00 sec)
  142. Query OK, 0 rows affected (0.00 sec)
  143. --
  144. -- REPEAT 循环
  145. --
  146. -- REPEAT 语法
  147. [begin_label:] REPEAT
  148. statement_list
  149. UNTIL search_condition
  150. END REPEAT [end_label]
  151. mysql> delimiter //
  152. mysql> create procedure pcd_test_4(in param_1 int)
  153. -> begin
  154. -> SET @x = 0; -- 没有使用declare,所以x是会话级别的
  155. -> REPEAT
  156. -> SET @x = @x + 1;
  157. -> UNTIL @x > param_1 END REPEAT;
  158. -> end;//
  159. Query OK, 0 rows affected (0.01 sec)
  160. mysql> delimiter ;
  161. mysql> call pcd_test_4(10);
  162. Query OK, 0 rows affected (0.00 sec)
  163. mysql> select @x; -- x是会话级别的
  164. +------+
  165. | @x |
  166. +------+
  167. | 11 | -- 一共循环11次(10>10 False11 > 10True,才跳出)
  168. +------+
  169. 1 row in set (0.00 sec)
  170. --
  171. -- loop 循环
  172. --
  173. -- loop语法
  174. [begin_label:] LOOP
  175. statement_list
  176. END LOOP [end_label]
  177. -- ITERATE label相结合,表示继续从label处执行
  178. -- LEAVE label相结合,表示从label 标记的代码段离开
  179. -- loop 例子
  180. mysql> delimiter //
  181. mysql> create procedure pcd_test_5(in param_1 int)
  182. -> begin
  183. -> test_label: loop
  184. -> set param_1 := param_1 + 1; -- 参数累加
  185. -> if param_1 < 10 then -- 如果累加的值小于10
  186. -> iterate test_label; -- 继续执行 标签 test_label
  187. -> end if;
  188. -> leave test_label; -- 如果>=10则离开这个test_label(loop)
  189. -> end loop test_label;
  190. -> set @x = param_1; -- 设置会话级别的变量
  191. -> end;//
  192. Query OK, 0 rows affected (0.02 sec)
  193. mysql> delimiter ;
  194. mysql> call pcd_test_5(5); -- 5<10 ,累加5次后>=10true,离开循环
  195. Query OK, 0 rows affected (0.00 sec)
  196. mysql> select @x;
  197. +------+
  198. | @x |
  199. +------+
  200. | 10 | -- 累加到10 param_1 赋值给 x, 即为10
  201. +------+
  202. 1 row in set (0.00 sec)
  203. -- 老师给出的例子, 阶乘
  204. mysql> create table test_proc_1(a int, b int); -- 给一个存放数据的表
  205. Query OK, 0 rows affected (0.15 sec)
  206. mysql> delimiter //
  207. mysql> create procedure proc_test1(in total int, out res int)
  208. -> begin
  209. -> declare i int;
  210. -> set i := 1;
  211. -> set res := 1;
  212. -> if total <= 0 then
  213. -> set total := 1;
  214. -> end if;
  215. -> while i <= total do
  216. -> set res := res * i;
  217. -> insert into test_proc_1 values(i, res);
  218. -> set i := i + 1;
  219. -> end while;
  220. -> end;//
  221. Query OK, 0 rows affected (0.01 sec)
  222. mysql> delimiter ;
  223. mysql> set @res_value := 0;
  224. Query OK, 0 rows affected (0.00 sec)
  225. mysql> call proc_test1(5, @res_value); -- 因为resout变量,要预先有这个变量,这里上面设置了res_value(实参和形参不必同名)
  226. Query OK, 1 row affected (0.15 sec)
  227. mysql> select @res_value;
  228. +------------+
  229. | @res_value |
  230. +------------+
  231. | 120 | -- 5的阶乘的结果是120
  232. +------------+
  233. 1 row in set (0.00 sec)
  234. mysql> select * from test_proc_1;
  235. +------+------+
  236. | a | b |
  237. +------+------+
  238. | 1 | 1 |
  239. | 2 | 2 |
  240. | 3 | 6 |
  241. | 4 | 24 |
  242. | 5 | 120 | -- 每次insert的结果
  243. +------+------+
  244. 5 rows in set (0.00 sec)

作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/wgmill 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。