创建存储过程
drop procedure if exists [存储过程名] ;
delimiter [结束标记]
create procedure [存储过程名]([参数1], [参数2] ...)
begin
[存储过程体(一组合法的sql语句)]
end [结束标记]
delimiter ;
参数,其格式为 [in|out|inout] parameter_name type
in #表示输入参数;
out #表示输出参数;
inout #表示此参数既可以输入也可以输出;
param_name #表示参数名称;
type #表示参数的类型。
delimiter [结束标记] 本身与存储过程的语法无关,用于表示SQL语句的结束。
后一个命令 delimiter ; 将 分隔符 改回 分号 ,用于告诉SQL引擎,遇到 分号 就可以提交了。
因为 SQL引擎 执行时,遇到分号(;)表示一个SQL语句的结束,会把这个SQL进行提交。
但是 存储过程和自定义函数,功能比较复杂,里面有好多条的SQL语句, 我们希望SQL引擎把 这一个存储过程或函数当成一个整体提交 (即原子性),而不是每段SQL语句遇到分号(;)就提交,这就无法保证完整性。
为了解决SQL执行引擎遇到分号提交的问题,就要使用 delimiter 定义一个新的结束标记 ,只不要是分号, SQL引擎就不会提交,这样保证 存储过程和自定义函数 的整体性。
所以,SQL 的 delimiter 的结束标记 不能定义为分号(;),一般使用特殊字符,如$ 、//、/ 等。
begin...end 语句块。 在 sql 语句,如果包含多条语句, 我们需要把多条语句放到 begin...end 语句块中。begin...end 块可以嵌套,同一组的SQL 代码放到 一个 begin...end 块,层层分开, 大的好处是便于阅读 。 如果仅仅一条sql语句,则可以省略 begin end 。
begin...end 相当于 java 语言中的 { } 。如果 if 内只有一条SQL时,{ } 可以省略,同样,begin...end 也可以省略。
public int method(int param){
int result=;
if(param==1){
result=......
}else if{param==2}{
result=......
}else{
result=......
}
return result;
}
public int method(int param){
int result=;
// 当 if 内只有一条SQL时,{ } 可以省略
if(param==1)
result=......
else if{param==2}
result=......
else
result=......
return result;
}
调用存储过程
call [存储过程名]([ proc_parameter [,proc_parameter ...]])
call [存储过程名]
说明:
存储过程修改 : 修改存储过程,就是删除重建。
删除存储过程: drop procedure [if exists] sp_name
drop table if exists `t_user`;
create table `t_user` (
`id` int not null auto_increment,
`name` varchar(20) not null,
primary key (`id`)
) engine=innodb auto_increment=1 default charset=utf8;
drop procedure if exists myproc1;
delimiter $
create procedure myproc1()
begin ## 下面只有一条语句,begin end 可以省略
insert into t_user values(null, 'Jas'),(null, 'Joy');
end $
delimiter ;
调用,并查看结果:
drop procedure if exists myproc2;
delimiter $
create procedure myproc2(in userId int)
begin
select name from t_user where id = userId;
end $
delimiter ;
调用,并查看结果:
drop procedure if exists myproc3;
delimiter $
create procedure myproc3(in userId int, out username varchar(20))
begin
select name into username # 将查询到的用户名赋值给 username
from t_user where id = userId;
end $
delimiter ;
调用,并查看结果:
drop procedure if exists myproc4;
delimiter $
create procedure myproc4(inout a int)
begin
set a = a * 2;
end $
delimiter ;
调用存储过程,并查询结果:
delimiter $$
use `exam9` $$ ## exam9 是数据库
drop procedure if exists `updateStatus` $$ ## 如果存在,就删除
create procedure `updateStatus`()
begin
update exam set `status`="已结束" where `status` != "已结束" and (now() - endtime)> ;
update exam set `status`="正在答题" where `status` != "已结束" and ( now() - starttime)>=
and (now() - endtime)<=;
update haulinfo set bigstatus="已结束" where bigstatus != "已结束" and (curdate() - bigenddate)>;
update haulinfo set bigstatus="进行中" where (curdate() - bigenddate)<= and (curdate() - bigbegindate)>=;
update exam set bigstatus=(select bigstatus from haulinfo where bigid=exam.bigid);
end $$
delimiter ;
from 关键字的后面。 SQL 语句中不可用存储过程,而可以使用函数。自定义函数 就像是 abs() 、 concat() 内建函数一样去扩展 mysql 。
所以,udf 是对 mysql 功能的一个扩展。
drop function if exists [函数名];
delimiter [结束标记]
create function [函数名]([参数1], [参数2] ...) returns [返回值类型]
begin
[方法体]
return [返回值];
end [结束标记]
delimiter ;
参数,其格式为param_name type,如username varchar(20) 。
删除 udf: drop function [函数名]
3udf : select [函数名](param_value, ...)
t_user 表中的数据:
查询 t_user 中的数据行数,并返回。
drop function if exists myfun1;
delimiter $
create function myfun1() returns int
begin
declare sum int default ; # 定义局部变量 sum,默认值为 0
select count(*) into sum # 将查询的结果赋值给 sum
from t_user;
return sum;
end $
delimiter ;
调用结果:
drop function if exists myfun2;
delimiter $
create function myfun2(userId int) returns varchar(20)
begin
set @username=''; # 定义系统会话变量
select name into @username # 将用户名赋值给 username
from t_user
where id = userId;
return @username;
end $
delimiter ;
查看结果:
delimiter //
create function if exist deleteById(uid smallint unsigned) returns varchar(20)
begin
delete from t_order where id = uid;
return (select count (id) from son);
end //
delimiter ;
delimiter // 表示 将默认的结束符由 ; 改为 // ,以后的sql语句都要以 // 作为结尾 。
returns varchar(20) 声明 返回值 是 20位长度的字符串 。
returns int 声明返回值 int 。
reurn 语句 也包含在begin...end 中。
declare var_name[,varname]...date_type [default value];
简单来说就是:
declare 变量1[,变量2,... ]变量类型 [default 默认值]
这些变量的作用范围是在begin…end程序中,而且定义局部变量语句必须在begin…end的行定义
delimiter //
create function addNum(x smallint unsigned, y smallint unsigned) returns smallint
begin
declare a, b smallint unsigned default 10; ### 定义局部变量
set a = x, b = y;
return a+b;
end //
delimiter ;
上边的代码只是把两个数相加,当然,没有必要这么写,只是说明局部变量的用法,还是要说明下:这些局部变量的作用范围是在 begin...end 程序中
作用域:针对于所有会话(连接)有效,但不能跨重启。重启后,配置失效。
# 查看所有全局变量
show global variables;
# 查看满足条件的部分系统变量
show global variables like '%char%';
# 查看指定的系统变量的值
select @@global.autocommit;
# 为某个系统变量赋值
set @@global.autocommit=;
set global autocommit=;
作用域:针对于当前会话(连接)有效
系统变量,如果不加 global 和 session ,则默认就是 session 。
# 查看所有会话变量
show session variables; ## 等价于 show variables;
# 查看满足条件的部分会话变量
show session variables like '%char%';
# 查看指定的会话变量的值
select @@autocommit;
select @@session.tx_isolation;
# 为某个会话变量赋值
set @@session.tx_isolation='read-uncommitted';
set session tx_isolation='read-committed';
作用域: 用户变量 在当前连接(即当前会话)中都有效。
同一个用户变量,前后可以接收不同类型的赋值。
age 是 int
name 是varchar(20)
set @tmpVal = age; ## 将age的值赋给 @tmpVal
set @tmpVal = name; ## 将name的值赋给 @tmpVal
set @变量名=值;
set @变量名:=值;
select @变量名:=值;
## 方式一:一般用于赋简单的值
set 变量名=值;
set 变量名:=值;
select 变量名:=值;
## 方式二:一般用于赋表 中的字段值
select 字段名或表达式 into 变量
from 表;
select @变量名;
作用域: 局变变量在 begin end 语句中有效,超过范围即失效。
declare 变量名 类型 【default 值】;
declare name varchar(20) ;
declare num int default ;
局部变量 必须在 begin end 的行 。
# 方式一:一般用于赋简单的值
set 变量名=值;
set 变量名:=值;
select 变量名:=值;
# 方式二:一般用于赋表 中的字段值
select 字段名或表达式 into 变量
from 表;
select 变量名
set autocommit=; ## 1、取消自动提交
start transaction; ## 2、开启事务
要执行的操作
commit; ## 3、提交事务
rollback; ## 4、回滚事务
begin
set autocommit=; ## 取消自动提交
start transaction; ## 开启事务
要执行的操作
commit; ## 提交事务
end ;
在事务中,设置保存点,当回滚时,能回滚到这个保存点,但是保存点之前的执行不会回滚。
set autocommit=; ## 取消自动提交
start transaction;
..... ## SQL语句
savepoint aa; ## 设置保存点,aa 是自定义的名称,保持
..... ## SQL语句
rollback to aa ## 回滚到保存点。 但是保存点前面执行的SQL执行依然有效。
存储过程 和 函数 中可以使用 流程控制语句 来 控制SQL 的执行。
mysql中可以使用 if 、case 、loop、leave、iterate 、repeat和 while 语句 来进行流程控制。
每个流程中可能包含一个单独语句,或者是使用 begin...end 构造的复合语句,构造可以被嵌套。
if(条件,值1,值2)
如果条件成立,则返回 值1,否则返回 值2
特点:可以用在任何位置。
根据是否满足条件,将执行不同的语句。
特点:
与 if 函数 的不同,这个if 条件只能用在 begin end 中 !!
if 表达式1 then 语句1;
elseif 表达式2 then 语句2;
...
else 语句n;
end if;
特点:只能用在 begin end 中 !!
注意: mysql还有一个if()函数,不同于这里描述的 if 语句。
if 示例:
if age>20 then
set @count1=@count1+1;
elseif age=20 then
set @count2=@count2+1;
else
set @count3=@count3+1;
end if;
说明:
end if 来结束。case when 也用来进行条件判断,其可以实现 比 if 更复杂的条件判断。
类似于 switch
case 表达式
when 值1 then 结果1或语句1 ## 如果是语句,需要加分号
when 值2 then 结果2或语句2 ## 如果是语句,需要加分号
...
else 结果n或语句n ## 如果是语句,需要加分号
end 【case】 ## 如果是放在begin end中,则结尾处需要加上case,如果放在select后面不需要
begin end 中,则需要在每个 语句后面加 分号,case 结尾处加 case ;case 。
case
when 表达式1 then 结果1或语句1 ## 如果是语句,需要加分号
when 表达式2 then 结果2或语句2 ## 如果是语句,需要加分号
...
else 结果n或语句n ## 如果是语句,需要加分号
end 【case】 ## 如果是放在begin end中,则结尾处需要加上case,如果放在select后面不需要
这个两个语法大的区别。
loop 可以使某些特定的语句重复执行,实现一个简单的循环。
但是 loop 本身没有停止循环的语句,必须使用 leave、iterate 等才能停止循环。
[begin_label:] loop
statement_list
end loop [end_label]
add_num: loop
set @count=@count+1;
end loop add_num ;
end loop 结束。leave 用于跳出循环。leave 用于 loop、repeat、while ,中断 并跳出循环。
leave label
label 表示 循环的标志。
add_num: loop
set @count=@count+1;
if @count=100 then
leave add_num ;
end loop add_num ;
循环执行 count 加1的操作。当 count 的值等于100时,则leave语句跳出循环。
iterate 也是跳出循环。但是,iterate 语句是跳出本次循环,然后直接进入下一次循环。
iterate 用于 loop、repeat、while 语句跳过本次循环。
iterate label
label 表示循环的标志。
add_num: loop
set @count=@count+1;
if @count=100 then
leave add_num ;
else if mod(@count,3)= then
iterate add_num;
select from employee ;
end loop add_num ;
说明:
leave 和 iterate 都用来跳出循环语句,但两者的功能是不一样的。
repeat 是有条件控制的循环。当满足特定条件时,就会跳出循环语句。
repeat
statement_list
until search_condition # until 后面没有分号(;),否则 报错
end repeat;
repeat
set @count=@count+1;
until @count=100
end repeat ;
循环执行count 加1的操作。
当 count 值为10 0时 结束循环。
repeat循环都用end repeat结束。
while 也是有条件控制的循环语句。但while 和 repeat 是不一样的。
while 是当满足条件时,执行循环内的语句。
while search_condition do
statement_list
end while ;
while @count<100 do
set @count=@count+1;
end while ;
delimiter $$
drop procedure if exists `sp_testloop` $$
create procedure `sp_testloop`(
in p_number int, #要循环的次数
in p_startid int #循环的起始值
)
begin
declare v_val int default ;
set v_val=p_startid;
loop_label: loop #循环开始
set v_val=v_val+1;
if(v_val>p_number)then
leave loop_label; # 终止循环
end if;
end loop;
select concat('testloop_',v_val) as tname;
end $$
delimiter ;
call sp_testloop(1000,);
delimiter $$
drop procedure if exists `sp_test_while`$$
create procedure `sp_test_while`(
in p_number int, #要循环的次数
in p_startid int #循环的起始值
)
begin
declare v_val int default ;
set v_val=p_startid;
outer_label: begin #设置一个标记
while v_val<=p_number do
set v_val=v_val+1;
if(v_val=100)then
leave outer_label; #满足条件,终止循环,跳转到 end outer_label标记
end if;
end while;
select '我是while外,outer_label内的SQL';## 这句SQL在outer_label代码块内,所以level后,这句SQL将不会执行;
#只要是在outer_label代码块内 任意位置 Leave outer_label,那么Leave后的代码将不再执行
end outer_label;
select concat('test',v_val) as tname;
end$$
delimiter ;
call sp_test_while(1000,);
delimiter $$
drop procedure if exists `sp_test_repeat`$$
create procedure `sp_test_repeat`(
in p_number int, #要循环的次数
in p_startid int #循环的起始值
)
begin
declare v_val int default ;
set v_val=p_startid;
repeat #repeat循环开始
set v_val=v_val+1;
until v_val > p_number #终止循环的条件,注意这里不能使用';'分号,否则报错
end repeat; #循环结束
select concat('test',v_val) as tname;
end$$
delimiter ;
call sp_test_repeat(1000,);
来源:https://xiaojin21cen.blog.csdn.net/ article/details/105596615
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31537575/viewspace-3123538/ ,如需转载,请注明出处,否则将追究法律责任。