前言
存储过程(Stored Procedure)是一组预定义的SQL语句集合,它们被保存在数据库中并可供重复调用。存储过程可以接受参数、执行查询和更新操作,并返回结果。使用存储过程,可以实现复杂的业务逻辑和数据操作,提高数据库应用的性能和安全性。
创建储存过程
以下是MySQL存储过程的基本语法结构:
create procedure procedure_name (IN|OUT|INOUT)
begin
-- 执行的sql语句和操作
end;
存储过程可以使用IN、OUT和INOUT参数来传递数据。IN参数用于向存储过程传入值,OUT参数用于从存储过程返回值,而INOUT参数则可用于双向传递数据。每个参数都需要指定名称和数据类型。
存储过程的主体部分包括BEGIN和END之间的SQL语句和操作。在存储过程中,可以包含变量、流程控制语句(如IF、WHILE)、条件语句、循环语句等,以实现复杂的逻辑处理。
示例:
-- 创建一个实现加法的储存过程,a和b为输入参数,c为输出参数
create procedure pro_add (in a int,in b int,out c int)
begin
set c=a+b; -- set用于设置或修改变量
end;
调用储存过程
在创建储存过程后,可以使用CALL语句调用它。
示例:
调用以上加法储存过程
set @c=0; -- 设置变量@c用来接收值
call pro_add(2,5,@c); -- 调用储存过程
select @c from dual; -- 查询变量@c的值(dual为系统表,定义的变量值都储存在其中)
@c|
--+
7|
储存过程中变量的使用
在SQL中,变量可以用于存储临时数据,并在查询或存储过程的执行过程中进行操作和引用。
两种常见的变量类型:局部变量和用户变量。
- 局部变量: 局部变量是在存储过程、函数或批处理中声明的变量,其作用范围仅限于所在的代码块或语句。局部变量通常用于存储临时数据,在代码块内进行计算和操作。
局部变量可以使用DECLARE语句进行声明,并且必须在使用之前先进行声明。
语法:
declare attr_name data_type [default value];
示例:
create procedure pro_test1(in a int,out b int)
begin
declare x int default 1; -- 定义x int类型 默认值为1
declare y int default 2;
set x=a*a;
set y=a/2;
set c=x+y;
end;
- 用户变量: 用户变量是由用户自定义并在当前会话中使用的变量,相当于全局变量。用户变量的作用范围可以涵盖整个会话,对话的所有语句都可以引用和修改这些变量。
用户变量通常以@符号开头,但不同的数据库管理系统可能对用户变量的命名规则有所差异。一般情况下,用户变量可以在任何查询语句中使用,并且无需事先声明。
例如:
set @c=0;
不管是局部变量还是用户变量都可以用set来修改变量的值。
储存过程中流程的控制
分支语句
IF语句
if condition then
statements;
elseif condition then
statements;
else
statements;
end if;
其中,condition是需要判断的条件表达式,statements是满足条件时需要执行的代码块。
CASE语句
CASE语句有两种形式:简单CASE表达式和搜索CASE表达式。
- 简单CASE表达式:简单CASE表达式基于一个表达式的值来匹配多个可能的结果。
语法:
case expression
when value1 then
statements1;
when value2 then
statements2;
...
else
statementsN;
end case;
其中,expression是需要比较的表达式,value1、value2等是可能匹配的值,statements1、statements2等是与匹配值对应的代码块,ELSE子句是可选的,默认情况下当没有匹配时执行的代码块。
- 搜索CASE表达式:搜索CASE表达式根据一系列的条件进行匹配,执行与第一个满足条件的分支相关联的代码块。
语法:
case
when condition1 then
statements1;
when condition2 then
statements2;
...
else
statementsN;
end case;
其中,condition1、condition2等是需要进行判断的条件表达式,statements1、statement2等是与条件对应的代码块,ELSE子句是可选的,默认情况下当没有条件匹配时执行的代码块。
循环语句
- WHILE循环:WHILE循环会根据特定的条件来判断是否继续执行循环内的代码块。
语法:
while condition do
statements;
end while;
其中,condition是需要判断的条件表达式,statements是需要重复执行的代码块。
- REPEAT循环:REPEAT循环会先执行一次代码块,然后根据条件判断是否继续执行循环。
语法:
repeat
statements;
until condition end repeat;
其中,statements是需要被重复执行的代码块,condition是一个条件表达式,判断是否继续执行循环。
- LOOP循环:LOOP循环会无限循环执行其中的代码块,直到遇到LEAVE语句或满足某种条件时跳出循环。
语法:
loop_label:loop
statements;
if condition then
leave loop_label;
end if;
end loop loop_label;
其中,loop_label是标识循环的名称,statements是需要被重复执行的代码块,condition是需要判断的条件表达式。
储存过程管理
查询储存过程
-- 查询所有储存过程
show procedure status;
查询结果:
-- 查询指定数据库的储存过程
show procedure status where db='test2';
查询结果:
-- 查询储存过程的创建细节
show create procedure test2.pro_add;
查询结果:
修改储存过程
当你想要修改一个已经存在的储存过程时,可以使用ALTER PROCEDURE语句。
语法:
alter procedure procedure_name [characteristic ...]
procedure_definition
其中,procedure_name
是要修改的存储过程的名称。characteristic
是可选的特征列表(例如指定安全权限、确定语言等),procedure_definition则是存储过程的新定义,包括参数、变量、逻辑和SQL语句等。
在MySQL中,你可以使用特征(characteristics)来定义存储过程的属性和行为。下面是一些常用的特征:
- DETERMINISTIC: 表示存储过程是确定性的,即对于给定的输入参数,每次执行都会得到相同的结果。这个特征可以提供一些性能优化。
- NOT DETERMINISTIC: 表示存储过程是非确定性的,即对于给定的输入参数,每次执行可能会得到不同的结果。这是默认的特征。
- CONTAINS SQL: 表示存储过程包含SQL语句。这是默认的特征。
- NO SQL: 表示存储过程不包含SQL语句,通常用于执行计算或控制逻辑。
- READS SQL DATA: 表示存储过程读取数据,但不修改数据。这是默认的特征。
- MODIFIES SQL DATA: 表示存储过程修改数据。
- SQL DATA ACCESS {CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}: 通过这个特征,你可以明确指定存储过程的数据访问方式。
示例:
-- 创建储存过程
create procedure greet()
reads sql data
begin
select 'Hello,world!';
end;
-- 修改储存过程特征
alter procedure greet not determinstic;
删除储存过程
语法:
drop procedure procedure_name;
其中,procedure_name是要删除的储存过程的名称。
游标
在Mysql中,使用储存过程和游标可以完成对查询结果集的遍历和处理。
声明游标
declare cursor_name cursor for select_statement;
其中,cursor_name是游标的名称,select_statement是用于获取结果集的查询语句。
打开游标
open cursor_name;
获取数据
fetch cursor_name into variable_list;
其中,variable_list是一个变量列表,用于接收结果集中的列值。可以使用多个变量来接收不同列的值。
关闭游标
close cursor_name;
示例:
-- 创建储存过程
create procedure pro_test2(out result varchar(200))
begin
declare cid int;
declare cname varchar(20);
declare str varchar(50);
declare num int;
declare i int;
-- 定义游标
declare cur cursor for select class_id,class_name from classes;
-- 获取表中记录数
select count(*) into num from classes;
set i=0;
open cur; -- 打开游标
-- 获取并处理数据
while i<num do
fetch cur into cid,cname; -- 获取数据
set str=concat_ws('~',cid,cname); -- 拼接数据
set result=concat_ws(',',result,str);
set i=i+1;
end while;
close cur; -- 关闭游标
end;
set @a='';
call pro_test2(@a);
-- 查询结果
select @a from dual;
@a |
---------------------------------------+
1~2022软件1,2~2022软件2,3~2022软件3,4~2022软件4|