MySQL学习(7)——存储过程

存储过程

(类似于其他编程语言的函数)

(学到现在发现 select 相当于其他编程语言里的 print)

不能修改存储过程,只能删除后重新创建;删除语法 drop procedure 存储过程名;

练习用的数据:

sql 复制代码
CREATE TABLE dept(
deptno INT PRIMARY KEY,
dname VARCHAR(20),
loc VARCHAR(20)
);
INSERT INTO dept VALUES(10, '教研部','北京'),
(20, '学工部','上海'),
(30, '销售部','广州'),
(40, '财务部','武汉');

create table if not exists emp(
empno int primary key,
ename varchar(20),
job varchar(20),
mgr int,
hiredate date,
sal numeric(8,2), -- 与 decimal 类型具有相同的含义,用于存储精确的小数值。
comm numeric(8, 2), -- 该字段的总长度为 8,其中小数位数为 2
deptno int,
FOREIGN KEY (deptno) REFERENCES dept(deptno) ON DELETE SET NULL ON UPDATE CASCADE
);

 INSERT INTO emp VALUES(1001, '甘宁', '文员', 1013, '2000-12-17', 8000.00, null, 20),
(1002, '黛绮丝', '销售员', 1006, '2001-02-20', 16000.00, 3000.00, 30),
(1003, '殷天正', '销售员', 1006, '2001-02-22', 12500.00, 5000.00, 30),
(1004, '刘备', '经理', 1009, '2001-4-02', 29750.00, null, 20),
(1005, '谢逊', '销售员', 1006, '2001-9-28', 12500.00, 14000.00, 30),
(1006, '关羽', '经理', 1009, '2001-05-01', 28500.00, null, 30),
(1007, '张飞', '经理', 1009, '2001-09-01', 24500.00, null, 10),
(1008, '诸葛亮', '分析师', 1004, '2007-04-19', 30000.00, null, 20),
(1009, '曾阿牛', '董事长', null, '2001-11-17', 50000.00, null, 10),
(1010, '韦一笑', '销售员', 1006, '2001-09-08', 15000.00, 0.00, 30),
(1011, '周泰', '文员', 1008, '2007-05-23', 11000.00, null, 20),
(1012, '程普', '文员', 1006, '2001-12-03', 9500.00, null, 30),
(1013, '庞统', '分析师', 1004, '2001-12-03', 30000.00, null, 20),
(1014, '黄盖', '文员', 1007, '2002-01-23', 13000.00, null, 10);

create table if not exists salgrade(
grade int primary key,
losal int,
hisal int
);
INSERT INTO salgrade VALUES(1,7000,12000),
(2,12010,14000),(3,14010,20000),(4,20010,30000);

定义变量

局部变量

default是设定默认值。

方式1:

方式2:

用户变量

系统变量

参数传递

in

练习:

1、 通过传入员工编号查询员工信息

2、 通过传入部门名和薪资,查询指定部门,并且薪资大于指定值的员工信息

sql 复制代码
-- 通过传入员工编号查询员工信息
delimiter $$
create PROCEDURE proc03(in p_empno int)
begin 

	select * from emp where empno = p_empno;
end $$
delimiter ;

call proc03(1001);

-- 通过传入部门名和薪资,查询指定部门,并且薪资大于指定值的员工信息
delimiter $$
CREATE PROCEDURE proc04(IN p_dname VARCHAR(20),in p_sal int)
BEGIN
 SELECT * FROM emp,dept WHERE emp.deptno=dept.deptno and dept.dname=p_dname and sal>p_sal;
 
END $$
delimiter ;
call proc04('销售部',13000);

out

sql 复制代码
-- 封装有参数的存储过程,传入员工编号,返回员工名字和薪资

delimiter $$
CREATE PROCEDURE proc05(IN p_empno INT,OUT p_ename VARCHAR(20),OUT p_sal INT)
BEGIN
	SELECT ename,sal into p_ename,p_sal  FROM emp WHERE empno=p_empno;
END $$
delimiter ;
call proc05(1001,@o_ename,@o_sal);
SELECT @o_ename,@o_sal;

inout

sql 复制代码
-- 传入员工名,拼接部门号,传入薪资,求出年薪
delimiter $$
CREATE PROCEDURE proc06(inout p_ename VARCHAR(20),inout p_sal int)
BEGIN
 select concat(deptno,'_',ename) into p_ename from emp where ename = p_ename;
 set p_sal=p_sal*12;
end $$
delimiter ;
set @o_ename = '关羽';
set @o_sal = 3000;
call proc06(@o_ename,@o_sal);
SELECT @o_ename,@o_sal;

流程控制

分支语句

if

练习:

-- 输入学生的成绩,来判断成绩的级别:

score<60:不及格

score >= 60,score<80:及格

score >= 80,score < 90 :良好

score >= 90,score <= 100:优秀

score>100:成绩错误

sql 复制代码
delimiter $$
create procedure proc07_if(in in_score int)
begin 
 if in_score <60
		then select '不及格';
 elseif in_score <80
		then select '及格';
 elseif in_score<90
		then select '良好';
 elseif in_score<=100
		then select '优秀';
 else 
		select '成绩错误';
 end if;

end $$
delimiter ;
call proc07_if(120);

-- 输入员工的名字,判断工资的情况。

sal<10000:试用薪资

sal >= 10000 and sal<20000:转正薪资

sal>=20000:元老薪资

sql 复制代码
delimiter $$
create procedure proc08_if(in in_name varchar(20))
BEGIN
	declare p_sal varchar(20);
	declare state varchar(20);
	select sal into p_sal from emp where ename=in_name;
	if p_sal <10000
		then set state = '试用薪资';
	elseif p_sal <20000
		then set state = '转正薪资';
	ELSE
		set state = '元老薪资';
	end if;
	select state;
end $$
delimiter ;
call proc08_if('张飞');
case

end case 结束要加分号;

1、支付方式:

1:微信支付、2:支付宝支付、3:银行卡支付、其他支付

2、 输入学生的成绩,来判断成绩的级别:

score<60:不及格

score >= 60,score<80:及格

score >= 80,score < 90 :良好

score >= 90,score <= 100:优秀

score>100:成绩错误

sql 复制代码
delimiter $$
create procedure proc09_case(in type int)
begin 
	declare res varchar(20);
	case type 
		when 1 then set res='微信支付';
		when 2 then set res='支付宝支付';
		when 3 then set res='银行卡支付';
		else set res='其他支付';
	end case;
	select res;
end $$
delimiter ;
call proc09_case(2);
-- -------------------------------------------------------------
delimiter $$
create procedure proc10_case(in in_score int)
begin 
 case
	when in_score <60
		then select '不及格';
	when in_score <80
		then select '及格';
	when in_score<90
		then select '良好';
	when in_score<=100
		then select '优秀';
	else 
		select '成绩错误';
 end case;

end $$
delimiter ;
call proc10_case(120);

循环语句

while(常用)

数据准备:

sql 复制代码
create table user(
	uid int PRIMARY KEY,
	uname varchar(50),
	password varchar(50)
);

1、向表中循环添加五条数据

sql 复制代码
delimiter $$
create procedure proc11_while(in in_count int)
begin 
	declare i int default 1;
	label:while i<=in_count do 
	insert into user(uid,uname,password) values(i,concat('user-',i),'123456');
	set i = i+1;
	end while label;
end $$
delimiter ;

call proc11_while(5);

运行结果:

(用truncate table user;把表中的数据清除了再对这个表进行新的插入操作)

2、当加了五条数据就跳出循环

sql 复制代码
delimiter $$
create procedure proc12_while(in in_count int)
begin 
	declare i int default 1;
	label:while i<=in_count do 
		insert into user(uid,uname,password) values(i,concat('user-',i),'123456');
		if i = 5 then 
			leave label;
		end if;
		set i = i+1;
	end while label;
end $$
delimiter ;

call proc12_while(10);

运行结果:

3、跳过编号5的数据插入

sql 复制代码
delimiter $$
create procedure proc13_while(in in_count int)
begin 
	declare i int default 0;
	label:while i<in_count do 
		set i = i+1;
		if i = 5 then 
			iterate label;
		end if;
		insert into user(uid,uname,password) values(i,concat('user-',i),'123456');
		
	end while label;
end $$
delimiter ;
repeat

(类似于do...while...循环)

1、向表中循环添加5条数据

sql 复制代码
delimiter $$
create procedure proc14_repeat(in cnt int)
begin
	declare i int default 1;
	REPEAT
		insert into user(uid,uname,password) values(i,concat('user-',i),'645645');
		set i=i+1;
	UNTIL i>cnt 
	END REPEAT;
end $$
delimiter ;
call proc14_repeat(5);
loop

1、向表中循环添加5条数据

sql 复制代码
delimiter $$
create procedure proc15_loop(in cnt int)
begin
	declare i int default 1;
	label:loop 
		insert into user(uid,uname,password) values(i,concat('user-',i),'645645');
		set i=i+1;
		if i>cnt then
			leave label;
		end if;
	END loop;
end $$
delimiter ;
call proc15_loop(5);

游标

用例:

需求:输入一个部门名,查询该部门员工的编号、名字、薪资,将查询的结果集添加游标。

sql 复制代码
delimiter $$
CREATE PROCEDURE proc16_cursor(in in_dname varchar(20))
BEGIN
	declare t_num int;
	declare t_name varchar(20);
	declare t_sal decimal(8,2);
	-- 声明游标
	declare my_cursor cursor for 
		select empno,ename,sal from dept a,emp b where a.deptno=b.deptno and a.dname= in_dname;
  -- 打开游标
  open my_cursor;
	label: LOOP
        -- 取值
		fetch my_cursor into t_num,t_name,t_sal;
		select t_num,t_name,t_sal;
  END LOOP label;

  -- 关闭游标
  close my_cursor;
END $$
delimiter ;

call proc16_cursor('销售部');

运行结果:(运行一次fetch查询结果表中的一行,所以有这么多结果)

按理来说,我们写的这个循环的一个死循环,但是它没有一直循环下去,而是在最后报错了,就是下图的情况。这和游标的读取方式有关,它是在表中一个一个往下查的,到查不到的时候就报错了。

异常处理

对于上面这种报错情况,就需要用到异常处理了。

大概就是你在写的时候遇到报错的一些情况之后,你来安排一下接下来怎么办,可以使代码顺利运行完成。

针对上面游标的情况,增加一个异常处理来进行优化:

sql 复制代码
delimiter $$
CREATE PROCEDURE proc17_handler(in in_dname varchar(20))
BEGIN
  -- 定义局部变量
	declare t_num int;
	declare t_name varchar(20);
	declare t_sal decimal(8,2);
	-- 定义标记值
	declare flag int default 1;
	-- 声明游标
	declare my_cursor cursor for 
		select empno,ename,sal from dept a,emp b where a.deptno=b.deptno and a.dname= in_dname;
	-- 定义句柄:异常处理方式
	/*
	1:异常处理完之后程序该怎么执行continue:继续执行剩余代码exi计:直接终止程序undo:不支持
  2:触发条件
	  条件码:
		     如1329
	  条件名:
		     SQLWARNING
         NOT FOUND
				 SQLEXCEPTION
   3:异常触发之后执行什么代码
	*/
	declare continue handler for 1329 set flag=0;
  -- 打开游标
  open my_cursor;
	label: LOOP
	  -- 取值
		fetch my_cursor into t_num,t_name,t_sal;
		if flag=1
			then select t_num,t_name,t_sal;
		else 
		  leave label;
		end if;
  END LOOP label;

  -- 关闭游标
  close my_cursor;
END $$
delimiter ;

call proc17_handler('销售部');

运行结果这个时候就不会有报错了:

相关推荐
小酒丸子3 小时前
AD学习笔记之异形焊盘
笔记·学习
renhongxia13 小时前
如何对海洋系统进行知识图谱构建?
人工智能·学习·语言模型·自然语言处理·自动化·知识图谱
知识分享小能手4 小时前
Redis入门学习教程,从入门到精通,Redis 数据操作:知识点详解与代码实战(2)
数据库·redis·学习
red_redemption4 小时前
自由学习记录(138)
学习
夏日听雨眠4 小时前
文件学习8
学习
炽烈小老头6 小时前
【每天学习一点算法 2026/03/17】括号生成
前端·学习·typescript
似水明俊德6 小时前
01-C#.Net-泛型-学习笔记
java·笔记·学习·c#·.net
今儿敲了吗6 小时前
python基础学习笔记第三章
笔记·python·学习
hua872227 小时前
Golang 构建学习
java·开发语言·学习