Part1 存储过程
存储过程是什么
存储过程是一系列的sql语句,目的是像函数一样返回一个结果。既然是可以看作为一个函数来使用,也就意味着这个函数能够满足某个功能,该功能需要输入参数,而不需要给你一个超长的select语句让你改数字。
好处:简单、安全、高性能
其他细节:对存储过程进行编写和访问执行是分开来的
执行存储过程
执行比较简单,用call + 存储过程名称就可以,还需要提供参数,前面记得加@
call productpricing(@pricelow,@pricehigh,@priceaverage); --productpricing是创建的一个存储过程的名称
创建、删除存储过程
关键词是create procedure + 存储过程名称,然后begin开始end结束,中间是希望这个“函数”要做的事情
删除操作不需要加括号,其他没什么要注意的
-- 创建存储过程
create procedure productpricing()
begin
select avg(prod_price) as priceaverage
from products;
end;
-- 删除存储过程
drop procedure productpricing;
这里注意,上面的这个创建不返回结果,是无效的,所以我们接下去看下如何将其变得更加完整。
含参数的存储过程
下面代码中创建了一个包含参数的存储过程,其中:
- ordertotal中含3个参数,前两个用IN是定义来两个表示存储过程要用到的变量,后一个OUT是定义了一个作为输出使用的变量ototal,格式是:[IN/OUT] 变量名 类型名称
- comment不是必要的语句,只是在你使用show procedure status查看所有存储过程时可以看到针对这个存储过程的注释
- 定义变量用declare,后面格式同1
- 在用select得到结果好,需要将结果INTO,即赋值到已经定义好数据类型的变量中,注意封号的使用
- IF语句用法较简单,IF xxx THEN xxx END IF,或IF xxx ELSE XXX END IF,或者 IF xxx ELSEIF XXX THEN xxx END IF,注意封号的使用
create procedure ordertotal(
IN onumber INT,
IN taxable BOOLEAN,
OUT ototal DECIMAL(8,2)
) comment 'obtain order total, alternatively whether taxable'
begin
-- 定义变量,decimal中8是数字总长度,2是小数部分长度
declare total DECIMAL(8,2);
declare taxrate INT DEFAULT 6;
-- get the order total
select sum(item_price*quantity)
from orderitems
where order_num = onumber
INTO total;
-- is this taxable?
IF taxable THEN
select total+total*taxrate/100 INTO total;
END IF;
select total INTO ototal;
end;
既然创建好存储过程了,我们来看看如何执行:
call ordertotal(2005,0,@total1);
select @total1;
cal ordertotal(2333,1,@total2);
select @total2
可以看到,2005对应onumber参数,0对应taxable参数,这里想着重提一下@total。你会发现我这里用的是@total,而我参数定义用的是ototal,那我可以定义为@ototal吗?其实没问题,但别忘加@即可。另外需要注意的是,当你执行call语句后,由于创建的存储过程有一个输出,而这个total输出是赋值到了@total这个变量中,所以不会返回值。如果要返回值,必须再加一个select将结果以查询的方式显示出来。
Part2 使用游标
游标是什么
在我看来,游标是对select查询到的结果再做细分处理。具体来说,游标可以对select查询出来的全部结果(也称:结果集)中选择性地选择行数据。之所以游标和存储过程写在一块,是因为在MySQL中,游标只能在存储过程中使用。
使用步骤
- 先定义游标变量,以及要对什么select语句对查询结果下手
- 打开游标,准备使用
- 对含有数据对游标,按需求检索出需要的行数据(用循环)
- 结束使用后关闭游标
我们来看下伪代码:
-- 第一步,declare 变量名 为 cursor for 某个select查询结果
declare mycursor cursor for
select xxx from xxxtable;
-- 第二步,打开这个叫mycursor的游标开始使用
open mycursor
--第三步,使用
因情况而不同
-- 第四步,关闭游标
close mycursor;
这基本就是游标的使用方法,接下去来看一个进阶的版本,其中用到了循环和条件语句
一个实例
首先我们需要这个存储过程:ordertotal,也就是上面讲存储过程的最后一个例子。ordertotal的输入是订单号,是否要税,以及将输出的结果赋值到一个变量。
create procedure ordertotal(
IN onumber INT,
IN taxable BOOLEAN,
OUT ototal DECIMAL(8,2)
) comment 'obtain order total, alternatively whether taxable'
begin
-- 定义变量,decimal中8是数字总长度,2是小数部分长度
declare total DECIMAL(8,2);
declare taxrate INT DEFAULT 6;
-- get the order total
select sum(item_price*quantity)
from orderitems
where order_num = onumber
INTO total;
-- is this taxable?
IF taxable THEN
select total+total*taxrate/100 INTO total;
END IF;
select total INTO ototal;
end;
那接下来如何将游标和存储过程一起使用呢,我们来设想这样一个情况:我们需要将所有订单,根据订单号所对应的货品总价加税后形成一张税后货价表,我们这么来做:
create procedure processorders()
begin
-- 定义需要的变量
declare done boolean default 0;
declare o int;
declare t decimal(8,2);
-- 定义一个游标
declare ordernumbers cursor
for
select ordernumber from orders;
-- 这行很重要,是说只有sql状态码是02000,指的是未找到。当未找到时,将原本默认done为0的数据赋值为1
declare continue handler for sqlstate '02000' set done=1;
-- 新建一个表,等会数据结果都会写入这个新表
create table if not exists ordertotals
(order_num int, total_price decimal(8,2));
open ordernumbers;
repeat
-- 获取指针指着的行对应的货品id
fetch ordernumber into o;
-- 调用名为ordertotal的存储过程返回税后价格,并存入变量t
call ordertotal(o,1,t);
-- 讲新数据添加入新表ordertotals
insert into ordertotals (order_num,total_price)
values(o,t);
until done end repeat;
-- 上面这句的意思是until done为1,即True时才退出循环
close ordernumbers;
end;
其他一些玩意:关于循环,除了repeat xxx until [condition] end repeat,还可以这样写:while [condition] do xxx end while