【MyQSL】存储过程

1.什么是存储过程

数据库中的存储过程有点类似编程中的函数,可以供外部环境在需要时调用,并且存储过程只需要编译一次,之后再用则无需进行在此编译。

2.存储过程的创建

代码

1
2
3
4
5
6
7
delimiter //
create procedure Test(in parameter01 int,out parameter02 varchar(45));
begin
-- 存储逻辑
end
//
delimiter ;

解析

  • delimiter //:更改MySQL中语句分隔符;,目的就是为了将存储过程作为一个整体,使MySQL中的存储逻辑中的;在代码编辑阶段不被编译器识别,//标识在两个//中间的逻辑为存储逻辑,告知MySQL其中的;不需要解释; 但是要记住,在用完//这个之后要记得将分隔符转回;,否则之后的语句也会使用//作为分隔符。其中//可以是任意字符或字符串。
  • create procedure Test(in parameter01 int , out parameter02 vachar(45)):创建一个存储过程Test,存储过程包含输入参数parameter01和输出参数parameter02,其中in标识输入参数,out标识输出参数,如果括号中不写标识in/out则默认为输入参数,其中输入参数只能用于从外界传入参数,输出参数只能用于返回结果,类似编程中的返回值。MySQL中也提供inout类型的参数,既可以作为输入参数使用也可以作为输出参数使用,但是不建议这么用,比较好的用法还是输入输出分开。
  • begin end:begin end用来标识一个语句块,必须承兑出现,可以用在任何地方,在存储过程中逻辑写在begin end块内。

3.存储过程的使用

1
call Test(1,@out_parameter);

存储过程的使用就如同函数调用一般,传入输入参数,并使用使用变量来接收输出参数。@out_parameter就是用来接收输出参数的变量。

4.存储逻辑

在编写存储过程时逻辑判断语句是一定会用到的,下面列举一些常用的逻辑判断语句及其用法。

if语句

MySQL中单独的if语句和程序编程中有所不同,单独的if语句一般嵌入其他语句中一起用,如:

1
select if(exc,'A','B');

当exc的值为true时,输出A,否则输出B,exc可以是一个变量也可以是是一个语句,同理A,B也可以是一个变量或是一个语句。

if esle语句

if esle语句与esle则有极大的不同,if else语句更接近编程中if esle

1
2
3
4
5
6
7
if exc1 then
-- 执行逻辑1;
elseif exc2 then
-- 执行逻辑2;
else
-- 执行逻辑3;
end if;

每一个if/elseif之后都需要跟一个then才能写执行逻辑,需要注意的是,then和执行逻辑之间没有;分隔。if语句结束时需要使用 end if;来告知MySQLif判断语句结束。同单独的if语句一样,if else中的exc也可以是变量和语句。

循环体

MySQL的循环体使用游标来实现,具体的我们先看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
delimiter //
-- 使用断面名删除断面的时间戳数据,此存储过程不允许删除断面
create procedure DeleteSurfaceDataByName(
in in_surface_name varchar(32),
in in_time_point_start varchar(32),
in in_time_point_end varchar(32),
out run_state bool
)
begin
-- 判断断面是否合法
if exists (select surface_no from surface_number where surface_name = in_surface_name) then
begin
declare num varchar(32) default null;
-- 游标的结束标志
declare done bool default false;
-- 为主键id创建游标
declare cur cursor for select id from surface_data where surface_name = in_surface_name;
-- 将结束标志关联到游标
declare continue handler for not found set done = true;
-- 打开游标
open cur;
-- 创建循环过程
delete_loop:loop
-- 从游标结果集中取值到num
fetch next from cur into num;
-- 游标后移
if done then
leave delete_loop;
end if;
-- 循环语句
begin
-- 场景1-删除当前段面中某一时段的水文数据
if in_time_point_start is not null and in_time_point_end is not null then
delete from surface_data where id = num and ascii(time_point) >= ascii(in_time_point_start)
and ascii(time_point) <= ascii(in_time_point_end);
-- 场景2-删除当前断面中某一时刻的水文数据
elseif in_time_point_start is not null and in_time_point_end is null then
delete from surface_data where id = num and time_point = in_time_point_start;
end if;
end;
-- 结束循环
end loop;
set run_state = true;
end;
else
set run_state = false;
end if;
end
//
delimiter ;
  • exists():和select搭配可以判断满足where条件的selete字段在from的表中是否存在
  • declare cur cursor for:和select语句搭配可以为select出来的结果集创建一个游标cur,而这个游标便是循环体的关键,游标就有点类似SLT中迭代器,可以逐一读取结果集中的数据。
  • declare continue handler for not found set done = true:光有游标还是无法实现循环体的,循环体还有一个很重要的标志–结束标志,这条语句便是为游标设置循环结束标志,这条语句和前面的declare done bool default false;搭配使用,done便是循环结束的标志,通过这条语句将游标和循环结束标志绑定起来。
  • open cur:上面仅仅是做好了使用循环体的前提,要想使用循环体还需要将游标打开,以便游标可以使用,open cur便是打开游标cur。
  • delete_loop:loop:这是真正的循环体的开始,开始一个循环题delete_loop,同时需要使用end loop;来标识循环题结束。
  • fetch next from cur into num:向游标cur指向的结果几种逐一读取数据到num变量中,这里要值意num变量和结果集中的数据类型要一至。
  • **if done then leave delete_loop end if;**:判断结束标志done,如果done等于true就继续执行循环体。
  • 在if done then leave delete_loop end if;和end loop之间的就是每次循环执行的语句了。

至此整个循环语句结束。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!