最近学习数据库语言sql,学到了存储过程和游标这一块,上课一点没听,可以说是全程懵逼。不过好在有个课后的实验,然而cmd中的报错往往极其粗糙,只会告诉你什么附近有错(有时候还是错的),在不知error了多少次,破防多少次之后终于完成了老师的任务,觉得有必要写一篇记录一下。
全程cmd深空黑背景,胆小勿入。
首先先给出我自己定义的表的结构:
简单介绍一下,这是一张员工信息表,empno就是员工号,ename员工姓名,job就是工作名,heredate工作时间,salary是薪资,comm是补贴,deptno是单位号,mgr是上司员工号。数据都是乱凑的,请勿当真。
存储过程在我理解来其实就是编程语言里面常说的函数,了解过其他语言的同学对于函数不会陌生,不过这个名字是真的高大上,本质就是把值传进去,然后计算好把值传出来。
下面直接贴出一道真题:
这道题就是根据输入empno然后你写一个存储过程,然后在其中计算号年收入,然后把答案输出。思路非常简单,就是根据员工号找到对应员工然后找到他的月薪和补贴(我就当做是每月补贴了),乘以一年的数量就是一年收入。
那么问题来了,该怎么写这个存储过程?存储过程的关键字是precedure,我们create一个新的precedure,然后前面说了存储过程就是函数,你得给他要算的人,所以把参数列表里面的empno前面加上一个in,表示是输入,因为你还要把值输出的,sql里面有没有return我不知道,但是我可以把参数列表里面的变量标记为out,表示输出,类似于其他语言的引用传参,如下;
create procedure cal_all_salary(in empno_in int,out all_salary double)
begin
过程体
end
cal_all_salary就是这个过程的名字,empno_in前面有了一个in,表示是输入,all_salary前面有个out,表示是输出,当然这个参数是需要你自己传进来的,然后begin和end就是过程的开始和结束的标志。
过程中要怎么写,无非就是把all_salary重新赋值,需要用到select...into变量from...方法,这个变量就是所需要赋值的。
select (comm+salary)*12 into all_salary from eemp where empno=empno_in;
当然这还不是一个完整的,因为还要涉及到过程的结束开始符,完整如下:
drop procedure if exists cal_all_salary;
delimiter //
create procedure cal_all_salary(in empno_in int,out all_salary double)
begin
select (comm+salary)*12 into all_salary from eemp where empno=empno_in;
end;
//
delimiter ;
因为是用记事本写的,所以也没啥缩进,格式也比较拉胯。第一句主要是为了避免名称重复,有重复就覆盖掉。delimiter 字符串表示把这个字符串作为结束符,我自己用//比较多,这是为了避免跟过程体内的 ; 搞混而设置的。
然后测试,可以利用set @变量名来定义一个变量:
set @ans=0;
cal_all_salary(1,@ans);
select @ans;
效果:
所以说存储本身就是为了完成一个特定的任务,把完成这个任务的方法存储起来,因此功能性也比较明确,方便了数据库的管理。
接下来是游标。游标在我觉得就是循环,把符合条件的打包成一个集合,然后一个个取出来判断,进行计算。
游标的使用格式如下:(抄了别人的)
DECLARE 迭代变量名1
.
.
.
DECLARE 游标名字 CURSOR FOR 查询语句;
open 游标名
while/repeat..
fetch 游标名 into var_name...
close 游标名
大致就是上面几个步骤。首先我先把有用的几个属性打包起来放进游标内,格式就是{[属性1,属性2...],[属性1,属性2...]...},每一个游标指向一行,有着多个属性的值,然后我利用循环一条一条取出来然后去做我想做的事情。这里的fetch就是取值,然后分别赋值给对应的变量。需要注意的就是打开和关闭。
最后贴一道题:
代码如下,应该是正确实现了的
drop procedure if exists avg_from_dept;
delimiter //
create procedure avg_from_dept(in dept_code int,out ans double)
begin
declare now_salary double;
declare no_data int default 0;
declare sum double default 0;
declare dept_cursor cursor for select salary from eemp where deptno=dept_code;
declare exit handler for not found set no_data = 1;
open dept_cursor;
repeat
fetch dept_cursor into now_salary;
set sum=sum+now_salary;
set ans=sum/(select count(*) from eemp where deptno=dept_code);
until no_data=1
end repeat;
close dept_cursor;
end;
//
delimiter ;
set @dept_in=1;
set @ans=0;
call avg_from_dept(@dept_in,@ans);
select @ans;
都是记事本写的,格式很差...