上一遍博客写了有关存储过程的语法知识 Mysql(7)---存储过程
游标
或许你在工做中不多用到,但用不到不表明不去了解它,但你真正须要它来解决问题的时候,再花时间去学习极可能会影响你的工做进度。
注意
:MySQL游标只能用于存储过程(和函数)。游标主要用于交互式应用。html
游标是一个存储在MySQL服务器上的数据库查询,它不是一条select语句,而是被该语句所检索出来的结果集。
接下来会对这句话作出进一步解释。java
好比有这么个语句mysql
SELECT name,age from person where age>10;
这个语句返回的极可能是多条语句,那么我如何遍历每一条数据呢,这个时候就须要游标,游标能够理解成java的List<Object>集合,存储了每个含有"name"和"age"的对象。接下来咱们就能够遍历集合中每个对象获取"name"和"age"。android
使用游标能够大体分为这么几步sql
声明游标
:这个过程其实是没有遍历数据的,它只是定义要使用的select语句来获取数据。数据库
打开游标
: 上面定义好后,那么这里就须要打开游标。这个过程用前面定义的select语句把数据实际检索出来。即这个步骤以后,咱们就能够遍历游标中的数据了。服务器
遍历数据
: 对于有数据的游标,根据须要取出各行的数据来进行必定的操做。iphone
关闭游标
: 使用完游标后,必定要关闭游标。函数
1)声明游标 oop
DECLARE cursor_name CURSOR FOR select_statement
这个语句声明一个游标。也能够在子程序中定义多个游标,可是一个块中的每个游标必须有惟一的名字。声明游标后也是单条操做的,可是SELECT语句不能有INTO子句。
2) 打开游标
OPEN cursor_name ;
这个语句打开先前声明的游标。
3) 遍历数据
FETCH cursor_name INTO var_name ;
这个语句用指定的打开游标读取下一行(若是有下一行的话),而且前进游标指针。
4) 关闭游标
CLOSE cursor_name ;
下面会用一个详细的例子来讲明,经过这个例子就能很明白游标是什么了。
例子所需表
CREATE TABLE IF NOT EXISTS `store` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `count` int(11) NOT NULL DEFAULT '1', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7; INSERT INTO `store` (`id`, `name`, `count`) VALUES (1, 'android', 15), (2, 'iphone', 14), (3, 'iphone', 20), (4, 'android', 5), (5, 'android', 13), (6, 'iphone', 13);
目的
:咱们如今要用存储过程作一个功能,统计iphone的总库存是多少,并把总数输出到控制台。
delimiter $ # 申明结束标志 drop procedure if exists StatisticStore$ # 若是存储过程已经存在则删除 CREATE PROCEDURE StatisticStore() BEGIN # 建立接收游标数据的变量 declare c int; # 获取单条纪录的数量 declare n varchar(20); #获取名称 # 建立总数变量 declare total int default 0; # 建立结束标志变量 declare done int default false; # 建立游标 获取name和count的集合 declare cur cursor for select name,count from store where name = 'iphone'; # 指定游标循环结束时的返回值 declare continue HANDLER for not found set done = true; # 设置初始值 set total = 0; # 打开游标 open cur; # 开始循环游标里的数据 read_loop:loop # 根据游标当前指向的一条数据 插入到上面申明的局部变量中 fetch cur into n,c; # 判断游标的循环是否结束 if done then leave read_loop; # 跳出游标循环 end if; # 获取一条数据时,将count值进行累加操做,这里能够作任意你想作的操做, set total = total + c; # 有loop 就必定要有end loop end loop; # 关闭游标 close cur; # 输出结果 select total; END $ # 调用存储过程 call StatisticStore()$
看输出结果 完美
在啰嗦几句
fetch
:是获取游标当前指向的数据行,并将指针指向下一行,当游标已经指向最后一行时继续执行会形成游标溢出。
使用loop循环游标时,他自己是不会监控是否到最后一条数据了,像下面代码这种写法,就会形成死循环;
read_loop:loop fetch cur into n,c; set total = total+c; end loop;
在MySql中,形成游标溢出时会引起mysql预约义的NOT FOUND错误,因此在上面使用下面的代码指定了当引起not found错误时定义一个continue 的事件,指定这个事件发生时修改done变量的值。
declare continue HANDLER for not found set done = true;
因此在循环时加上了下面这句代码:
#判断游标的循环是否结束 if done then leave read_loop; #跳出游标循环 end if;
若是done的值是true,就结束循环。继续执行下面的代码。
delimiter $ # 申明结束标志 drop procedure if exists StatisticStore3$ CREATE PROCEDURE StatisticStore3() BEGIN declare _n varchar(20); declare done int default false; declare cur cursor for select name from store group by name; #其实就是得到了两个名称的集合[android,iphone] declare continue HANDLER for not found set done = true; open cur; read_loop:loop fetch cur into _n; if done then leave read_loop; end if; begin declare c int; declare n varchar(20); declare total int default 0; declare done1 int default false; declare cur cursor for select name,count from store where name = _n; declare continue HANDLER for not found set done1 = true; set total = 0; open cur; # 这里游标名称和上面重复了,mysql默认就近原则 因此遍历的是最近的那么 但仍是很是不建议取同样的名称 iphone_loop:loop fetch cur into n,c; if done1 then leave iphone_loop; end if; set total = total + c; end loop; close cur; select _n,n,total; # select 只输出一次,并且是第一次遍历数据 end; end loop; close cur; END$ call StatisticStore3()$
执行结果(select 只输出一次,并且是第一次遍历数据)
只要本身变优秀了,其余的事情才会跟着好起来(少将10)