目录
iterate用法 相当于python中的 continue
一,概念
1,介绍.
存储过程其实就是python中的函数.
从mysql5.0以上开始支持存储过程.存储过程就是一组sql语句集,内部可以实现比较复杂的逻辑功能,可以输入参数,可以输出参数.
相当于编程语言(比如python,比如JavaScript)中的函数用法.
存储过程就是对数据库sql语言层面的代码进行模块化的封装和复用.
2,特性
封装性:即将一系列的操作或计算封装在一个可重用的单元中。这样,你可以通过调用这个单元(存储过程或函数)来执行封装好的代码,而不需要每次都重写相同的逻辑。
参数传递:可以接受参数,也可以返回结果(对于函数来说通常是单个值,而存储过程可以返回多个值,尽管方式可能不同)。
可重用性:两者都是为了提高代码的可重用性而设计的。
3,作用
除了首次执行需要编译和优化步骤,后续可以直接调用.
二,格式
简单的存储过程案例
假如有一个emp表
create database my_def; #建库
use my_def; #建表
delimiter $$$ #自定义分割符号,这个符号表示存储过程从这个符号这里开始,结束的时候也从这个符号结束
create procedure my_fn() #定义存储过程名称
begin #开始
select * from emp; #内部执行的sql语句
end $$$ #存储过程结束
delimiter; #恢复sql默认的分隔符号 ;
call my_fn(); #调用这个存储过程
以上代码 call 调用这个存储过程就可以查询emp表所有的信息.
基本格式:
delimiter 自定义分隔符号 #这个符号必须和end的分割符号相等
create procedure 函数名称(参数1,参数2,参数3……)
begin
sql 语句;
end 自定义分割符号 #必须和之前的分割符号相等
delimiter ;
三,变量
在存储过程中也支持自定义变量.
变量和其他编程语言一样,也分局部和全局.
1,局部变量
可以自定义,但是仅仅在begin和end之间生效,外部是无法访问的.
语法:
declare 变量名 类型 [default 默认值];
#示例一
declare var_flag int default 1;
#示例二
declare var_name varchar(20)
案例
---------------------------定义局部变量---------------------
delimiter ##
create procedure my_fn1()
begin
declare name varchar(20) default '凡梦';
select name;
end ##
delimiter;
call my_fn1()
结果
2,变量赋值
语法:set 变量=值
----------------修改局部变量--------------------
delimiter $$
create procedure my_fn2()
begin
declare name varchar(20) default '林宝玉';
set name = '林黛玉';
select name;
end $$
delimiter ;
call my_fn2()
结果
3,变量赋值二
从sql语句里面赋值
语法;select name into 变量名 from 表名;
假如有一个部门表 里面有个id是1001的人
--------------查询的时候带赋值------------
delimiter $$
create procedure my_fn3()
begin
declare name1 varchar(30);
select ename into name1 from emp where empno='1001';
select name1;
end $$
delimiter ;
call my_fn3();
结果
查询的时候带赋值并且修改值
----------------查询的时候带赋值并且修改值---------------
delimiter $$
create procedure my_fn4()
begin
declare name1 varchar(30);
select ename into name1 from emp where empno='1001';
set name1='甘宁1';
select name1;
end $$
delimiter ;
call my_fn4();
3,会话变量
用户自定义的变量,当前会话 连接有效,关闭本次会话,则变量失效.这个变量是存在内存之中的.
语法: @变量名 会话变量不需要提前声明,使用即声明.
会话变量可以在存储过程中使用,也可以在存储过中外使用.
-------------------定义会话变量-----------@变量名--------
--当前会话生效 变量存储在内存中
delimiter $$ --定义函数开始的符号
create procedure my_fn5()
begin
set @var_name='张三'; --设置全局变量 也就是会话变量
select @var_name; ---查询这个会话变量
end $$; --符号结束
delimiter ; --恢复到默认的分隔符号
call my_fn5(); ---调用函数
select @var_name; ----外面查看全局变量的值
会话变量对子查询的应用
--------------------子查询对变量的运用----------------------------
delimiter $$
create procedure my_fn6()
begin
declare ename1 varchar(20); ---定义一个ename1 局部变量
declare ejob1 varchar(20); ---ejob1 局部变量
select ename,job into ename1,ejob1 from emp where empno='1001';
--查询 当部门编号是1001的时候 查询他们的姓名和工作岗位
select * from emp where job = ejob1;
--查询 当工作岗位是 1001的编号的 工作岗位的时 拿到这个信息
end $$;
delimiter ;
call my_fn6();
结果
------------------------多个参数 查看--------------------
delimiter $$
create procedure my_fn7()
begin
declare ename1 varchar(20);
declare ejob1 varchar(20);
select ename,job into ename1,ejob1 from emp where empno='1001';
select ename1,ejob1;
end $$;
delimiter ;
call my_fn7()
3,系统变量
系统变量其实严格来说,应该是系统变量和全局变量.
系统变量在mysql文件夹中的my.ini配置文件中.如果要修改,可以更改这个配置文件,从而修改配置文件,让所有的用户都生效.
全局变量,就是我们在启动mysql的时候,服务器会自动将系统变量复制一份给我们当做会话变量.这个会话变量也是可以在存储过程中和存储过程外使用的.
语法: @@变量名
赋值语法:set @@变量名 = 值
-----------------------全局变量------------------------------------
show global variables ; -----查看全局变量
select @@auto_increment_increment; ----查看指定全局变量
系统变量存储在my.ini 配置文件中 我们每次开启一个会话,会复制一份系统变量作为会话变量供这个会话使用;
有的是只读的 有的是可以修改的 修改仅仅生效与这个会话
四,参数
1,in参数
in参数 ,表示是可以传入的数值或者变量, 传入了参数之后,我们在函数内部就可以使用这个变量了.
语法: 函数名(in 参数名 类型)
案例演示:
封装一个有参数的存储过程,存入员工编号,查找员工信息
--------------传入参数 封装函数 查询-------------
--封装存储过程 传入员工编号 查询员工信息
delimiter $$
create procedure my_fn8(in p_id varchar(20)) ---传入参数
begin
select * from emp where empno =p_id; ---使用参数
end $$;
delimiter ;
call my_fn8('1001'); ----
以上代码演示了 传入参数 1001 作为id被函数内的sql语句使用了.
下面代码演示传入多个参数的时候.
---------------传入多个参数 封装函数 做多表查询-----------------------
--封装存储过程,传入部门名和薪资 查询指定部门且薪资在某个范围内的值
delimiter $$
create procedure my_fn9(in p_name varchar(20),in p_sal varchar(20))
begin
select * from emp e,dept d
where e.deptno=d.deptno
and d.dname=p_name
and e.sal > p_sal;
end $$;
delimiter ;
call my_fn9('学工部',10000);
2,out参数
out 表示从函数内部返回值给调用者.
语法: 函数名(out 变量名 类型)
跟通俗的理解可以 理解为
return
案例演示:
------------------------返回值训练2 ----------------------------------
----out相当于是返回值 我们用一个容器接受 然后用会话变量来使用
-- 封装有参数的存储过程,传入员工编号,返回员工名字和薪资
delimiter $$
create procedure my_fn11(in p_id varchar(20),out o_name varchar(20),out o_sal varchar(20))
begin
select emp.ename,emp.sal into o_name,o_sal from emp where empno=p_id;
end $$
delimiter ;
call my_fn11('1002',@emp_name,@emp_sal);
select @emp_name,@emp_sal;
------------------------返回值训练2 ----------------------------------
----out相当于是返回值 我们用一个容器接受 然后用会话变量来使用
-- 封装有参数的存储过程,传入员工编号,返回员工名字和薪资
delimiter $$
create procedure my_fn11(in p_id varchar(20),out o_name varchar(20),out o_sal varchar(20))
begin
select emp.ename,emp.sal into o_name,o_sal from emp where empno=p_id;
end $$
delimiter ;
call my_fn11('1002',@emp_name,@emp_sal);
select @emp_name,@emp_sal;
3,inout参数
inout参数 表示外部传入的参数经过修改之后可以返回的变量,既可以使用传入变量的值也可以修改变量的值.即使函数执行完毕.
-----------------------------inout 传入值返回值一体-------------------------------------------
---- 传入员工名,拼接部门号,传入薪资,求出年薪
delimiter $$ ---定义分隔符
create procedure my_fn12(inout io_name varchar(40),inout io_sal varchar(20))
--创建 存储过程 名称 参数 inout 名字 类型
begin
select concat(empno,'~',ename) into io_name from emp where ename =io_name;
---查询我们传入的参数 然后拼接之后 再返回值给他
set io_sal =io_sal *12 ;
--使用我们传入的参数 然后*12赋值给他
end $$;
delimiter ;
set @myname='关羽'; --创建一个会话变量
set @mysal=3000; --创建一个会话变量
call my_fn12(@myname,@mysal) --调用我们定义的存储过程
select @myname,@mysal; --查看我们的2个会话变量
五,条件分支
1,if语句判断条件
和其他编程语言一样,sql的存储过程中也有if和else的用法.
格式:
if 条件1 then 结果1;
elseif 条件2 then 结果2;
elseif 条件3 then 结果3;
else 以上条件都不满足返回的结果
end if;
案例.输入学会的成绩,判断成绩的级别
delimiter $$
create procedure my_fn13(in soure int)
begin
if soure <60 then select '不及格';
elseif soure <80 then select '良好';
elseif soure <90 then select '优秀';
elseif soure <100 then select '优秀';
else select '未知成绩';
end if;
end $$;
delimiter ;
call my_fn13(0);
返回结果: 不及格
案例演示2 在sql查询语句中运用
比如输入员工名称,来判断工资的情况
-- 输入员工的名字,判断工资的情况。
###----------------------- 语句------ if else if 语句----------------------;
delimiter $$
create procedure my_fn14(in i_name varchar(20))
begin
declare res varchar(30);
declare i_sal int;
select sal into i_sal from emp where ename = i_name;
if i_sal < 2000 then set res ='穷鬼';
elseif i_sal<3000 then set res ='有点钱';
else set res='超级有钱';
end if;
select res;
end $$
delimiter ;
call my_fn14('关羽');
2 ,case语句判断条件
跟python中的case语法几乎一样.
case 条件 然后匹配固定值
语法:
case 字段
when 值1 then 结果1;
when 值2 then 结果2;
else 以上都不满足的结果;
end case;
##--根据姓名 查询部门名称 不连接多表;
# ------------------固定值案例
#case + when +then +else +end case 语句
delimiter $$
create procedure my_fn15(in i_name varchar(20),out res varchar(30))
begin
declare p_deptno varchar(30);
select deptno into p_deptno from emp where ename = i_name;
case p_deptno
when '10' then set res ='教研部';
when '20' then set res ='学工部';
when '30' then set res ='销售部';
when '40' then set res ='财务部';
else set res ='未知部门';
end case;
end $$
delimiter ;
call my_fn15('关羽',@ee_name);
select @ee_name;
案例二 case条件
##-------------------语句-------------------------
#case语句 条件筛选案例
delimiter $$
create procedure my_fn16(in soure int)
begin
case
when soure <60 then select '不及格';
when soure<80 then select '良好';
when soure<100 then select '优秀';
else select '未知成绩';
end case;
end $$
delimiter ;
call my_fn16(40);
call my_fn16(20);
call my_fn16(80);
六,循环
使用循环最大的好处就是我们可以批量创建表格,批量创建,修改,删除数据.
1,while循环
和常规编程语言一样,用法格式逻辑基本一样.
语法:
while 条件
do
循环体
循环终止条件
end while
代码案例 批量添加数据.
### 循环案例 while循环
create table user(
id int primary key auto_increment,
name varchar(30),
psd varchar(30)
);
delimiter $$
create procedure my_fn17(in i_count int)
begin
declare i int default 1;
while i < i_count do
insert into user value (i,concat('user_',i),round(rand()*1000*i,0) );
set i = i+1;
end while;
end $$
delimiter ;
call my_fn17(5);
truncate table user;
leave 用法
相当于python中break. 终于循环
案例:
#while循环案例 leave 演示
delimiter $$
create procedure my_fn18(in i_count int)
begin
declare i int default 1;
lable:while i<=i_count do
insert into user value (i,concat('user-',i),'123456');
if i = 5 then leave lable; #--结束循环
end if;
set i = i+1;
end while lable;
end $$
delimiter ;
truncate table user;
call my_fn18(10); #只有五条
iterate用法
相当于python中的 continue
案例:
#while 循环案例 iterate演示 相当于跳出
delimiter $$
create procedure my_fn19(in i_count int)
begin
declare i int default 0;
l1:while i<=i_count do
set i =i+1;
if i =5 then iterate l1; #如果循环到我这里 就跳过 后面的不执行了 然后循环在开启 继续在执行
end if;
insert into user value(i,concat('user-',i),'123456');
end while l1;
end $$
delimiter ;
truncate table user;
call my_fn19(10);
2,repeat循环
这个循环用法,无论条件如何都会执行一次
delimiter $$
create procedure my_fn20(in i_count int)
begin
declare i int default 1;
repeat
insert into user values (i,concat('user-',i),'1234');
set i =i+1;
until i>i_count
end repeat;
end $$
delimiter ;
truncate table user;
call my_fn20(10);
3,loop循环
loop循环本质是一个死循环,需要添加if条件 来终止循环
案例:
#loop 案例
delimiter $$
create procedure my_fn21(in i_count int)
begin
declare i int default 1;
li:loop
insert into user value (i,concat('user',i,i),'12345');
if i<i_count then leave li;
end if;
end loop li;
end $$
delimiter ;
truncate table user;
call my_fn20(10);
七,游标
游标是用来存储查询结果集的数据类型.在存储过程中和函数中可以使用游标 对结果集进行循环的处理,游标的使用包括,对永彪的声明,打开,取值,关闭
语法:
#声明游标
declare 游标名称 cursor for sql语句
#打开游标
open 游标名称
#取值游标
fatch 游标名称 into 变量1,变量2,变量3 ……
#关闭游标
close 游标名称
案例演示: 通过循环 使用游标抓取每一条数据
#--游标
use my_procedure;
delimiter $$
create procedure my_fn100(in i_name varchar(20))
begin
declare p_deptno varchar(20);
declare p_dnam varchar(20);
declare p_loc varchar(30);
declare i_count int;
declare i int default 1;
#创建游标
declare youbiao cursor for select empno , ename, sal
from dept a ,emp b
where a.deptno = b.deptno and a.dname = i_name;
#创建一个sql 获取终止条件
select count(*) into i_count
from dept a ,emp b
where a.deptno = b.deptno and a.dname = i_name;
#打开游标
open youbiao;
#取值游标
while i<i_count do
fetch youbiao into p_deptno,p_dnam,p_loc;
select p_deptno,p_dnam,p_loc;
set i = i+1;
end while;
#关闭游标
close youbiao;
end $$
delimiter ;
call my_fn100('销售部');
八,异常处理
和其他编程语言一样 存储过程中也可以使用异常处理,来捕捉异常,然后避免报错,从而继续执行后续的代码.
语法:
特别注意: 在语法中,变量声明、游标声明、handler声明是必须按照先后顺序书写的,否则创建存储过程出错。
案例:
use my_procedure;
delimiter $$
create procedure my_fn101(in i_name varchar(20))
begin
declare p_deptno varchar(20);
declare p_dnam varchar(20);
declare p_loc varchar(30);
declare i int default 1;
#创建游标
declare youbiao cursor for select empno , ename, sal
from dept a ,emp b
where a.deptno = b.deptno and a.dname = i_name;
#添加异常 handler 捕捉异常
# declare continue handler for NOT FOUND set i = 0;
#另外一种模式
declare exit handler for NOT FOUND set i = 0;
#打开游标
open youbiao;
#取值游标
li:loop
fetch youbiao into p_deptno,p_dnam,p_loc;
if i=1 then
select p_deptno,p_dnam,p_loc;
else leave li;
end if;
end loop li ;
#关闭游标
close youbiao;
end $$
delimiter ;
call my_fn101('销售部');
结果和游标结果一样