# 一、存储过程简介
```
SQL语句需要先编译然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,
经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。
```
## 二、存储过程的特点
### 优点
```
1、能完成较复杂的判断和运算
2、可编程行强,灵活
3、SQL编程的代码可重复使用
4、执行的速度相对快一些
5、减少网络之间的数据传输,节省开销
```
### 缺点
```
不易维护,阅读性差
```
## 三、创建一个简单的存储过程
1、创建存储过程的简单语法
``` sql
create procedure 名称()
begin
.........
end
```
2、创建一个简单的存储过程
```
create procedure testa()
begin
select * from users;
select * from orders;
end;
```
3、调用存储过程
```
call testa();
```
## 四、存储过程的变量
1、先通过一个简单的例子来学习变量的声明和赋值
```
create procedure test2()
begin
-- 使用 declare语句声明一个变量
declare username varchar(32) default '';
-- 使用set语句给变量赋值
set username='xiaoxiao';
-- 将users表中id=1的名称赋值给username
select name into username from users where id=1;
-- 返回变量
select username;
end;
```
2、概括
```
1.变量的声明使用declare,一句declare只声明一个变量,变量必须先声明后使用;
2.变量具有数据类型和长度,与mysql的SQL数据类型保持一致,因此甚至还能制定默认值、字符集和排序规则等;
3.变量可以通过set来赋值,也可以通过select into的方式赋值;
4.变量需要返回,可以使用select语句,如:select 变量名。
```
## 五、变量的作用域
1、变量作用域说明:
```
1.存储过程中变量是有作用域的,作用范围在begin和end块之间,end结束变量的作用范围即结束。
2.需要多个块之间传值,可以使用全局变量,即放在所有代码块之前
3.传参变量是全局的,可以在多个块之间起作用
```
2、通过一个实例来验证变量的作用域
注意:存储过程中变量的作用域,作用范围在begin和end块之间,end结束变量的作用范围即结束
## 六、存储过程参数
1、基本语法
```
create procedure 名称([IN|OUT|INOUT] 参数名 参数数据类型 )
begin
.........
end
```
存储过程的参数类型有:IN,OUT,INOUT,下面分别介绍这个三种类型:
2、存储过程的传出参数IN
说明:
```
1、传入参数:类型为in,表示该参数的值必须在调用存储过程事指定,如果不显示指定为in,那么默认就是in类型。
2、IN类型参数一般只用于传入,在调用过程中一般不作为修改和返回
3、如果调用存储过程中需要修改和返回值,可以使用OUT类型参数
```
3、存储过程的传出参数out
说明:
```
1、传出参数:在调用存储过程中,可以改变其值,并可返回;
2、out是传出参数,不能用于传入参数值;
3、调用存储过程时,out参数也需要指定,但必须是变量,不能是常量;
4、如果既需要传入,同时又需要传出,则可以使用INOUT类型参数
```
4、存储过程的可变参数INOUT
说明:
```
1、可变变量INOUT:调用时可传入值,在调用过程中,可修改其值,同时也可返回值;
2、INOUT参数集合了IN和OUT类型的参数功能;
3、INOUT调用时传入的是变量,而不是常量;
```
## 七、存储过程条件语句
1、基本结构
(1)、条件语句基本结构:
```
if() then...else...end if;
```
(2)、多条件判断语句:
```
if() then...
elseif() then...
else ...
end if;
```
2、实例
实例1:编写存储过程,如果用户userId是偶数则返回username,否则返回userId
```
create procedure test7(in userId int)
begin
declare username varchar(32) default '';
if(userId%2=0)
then
select name into username from users where id=userId;
select username;
else
select userId;
end if;
end;
```
实例2、存储过程的多条件语句应用示例
需求:根据用户传入的uid参数判断
(1)、如果用户状态status为1,则给用户score加10分;
(2)、 如果用户状态status为2,则给用户score加20分;
(3)、 其他情况加30分
```
create procedure test8(in userid int)
begin
declare my_status int default 0;
select status into my_status from users where id=userid;
if(my_status=1)
then
update users set score=score+10 where id=userid;
elseif(my_status=2)
then
update users set score=score+20 where id=userid;
else
update users set score=score+30 where id=userid;
end if;
end;
```
## 八、存储过程循环语句
1、while语句
while语句的基本结构
```
while(表达式) do
......
end while;
```
实例:
```
create procedure test9()
begin
declare i int default 0;
while(i<10) do
begin
select i;
set i=i+1;
insert into test1(id) values(i);
end;
end while;
end;
```
2、repeat语句
repeat语句基本的结构:
```
repeat...until...end repeat;
```
实例:
```
create procedure test10()
begin
declare i int default 0;
repeat
begin
select i;
set i=i+1;
insert into test1(id) values(i);
end;
until i>=10 -- 如果i>=10,则跳出循环
end repeat;
end;
```
概括:
until判断返回逻辑真或者假,表达式可以是任意返回真或者假的表达式,只有当until语句为真是,循环结束。
## 九、存储过程游标的使用
1、什么是游标
游标是保存查询结果的临时区域
2、示例
需求:编写存储过程,使用游标,把users表中 id为偶数的记录逐一更新用户名
```
create procedure test11()
begin
declare stopflag int default 0;
declare username VARCHAR(32);
-- 创建一个游标变量,declare 变量名 cursor ...
declare username_cur cursor for select name from users where id%2=0;
-- 游标是保存查询结果的临时区域
-- 游标变量username_cur保存了查询的临时结果,实际上就是结果集
-- 当游标变量中保存的结果都查询一遍(遍历),到达结尾,将变量stopflag设置为1,用于循环中判断是否结束
declare continue handler for not found set stopflag=1;
open username_cur; -- 打卡游标
fetch username_cur into username; -- 游标向前走一步,取出一条记录放到变量username中
while(stopflag=0) do -- 如果游标还没有结尾,就继续
begin
-- 在用户名前门拼接 '_cur' 字符串
update users set name=CONCAT(username,'_cur') where name=username;
fetch username_cur into username;
end;
end while; -- 结束循环
close username_cur; -- 关闭游标
end;
```
## 十、自定义函数
1、什么是自定义函数
函数与存储过程最大的区别是函数必须有返回值,否则会报错
2、说明:
```
1.创建函数使用create function 函数名(参数) returns 返回类型;
2.函数体放在begin和end之间;
3.returns指定函数的返回值;
4.函数调用使用select getusername()。
```
3、实例
需求:根据userid,获取accoutid,id,name组合成UUID作为用户的唯一标识
```
create function getuuid(userid int) returns varchar(64)
reads sql data -- 从数据库中读取数据,但不修改数据
begin
declare uuid varchar(64) default '';
select concat(accontid,'_',id,'_',name) into uuid from users where id=userid;
return uuid;
end;
```
## 十一、触发器
1、什么是触发器?
触发器与函数、存储过程一样,触发器是一种对象,它能根据对表的操作时间,触发一些动作,这些动作可以是insert,update,delete等修改操作。
2、实例
```
create trigger tr_users_insert after insert on users
for each row
begin
insert into oplog(userid,username,action,optime)
values(NEW.id,NEW.name,'insert',now());
end;
```
3、总结
```
1、创建触发器使用create trigger 触发器名
2、什么时候触发?after insert on users,除了after还有before,是在对表操作之前(before)或者之后(after)触发动作的。
3、对什么操作事件触发? after insert on users,操作事件包括insert,update,delete等修改操作;
4、对什么表触发? after insert on users
5、影响的范围?for each row
```
## 十二、流程控制
case分支
```
case ...
when ... then....
when.... then....
else ...
end case;
```
实例
```
create procedure testcate(userid int)
begin
declare my_status int default 0;
select status into my_status from users where id=userid;
case my_status
when 1 then update users set score=10 where id=userid;
when 2 then update users set score=20 where id=userid;
when 3 then update users set score=30 where id=userid;
else update users set score=40 where id=userid;
end case;
end;
```
## 十三、存储过程+event(事件)
个人博客:
名称:纯洁的麦田
链接:http://www.idearyou.cn/
描述:争取哪一天做上架构师
公众号:纯洁的麦田
另外:个人公众号,每天有新java文章,还有中高级面试题分享