mysql中游标的使用案例详解(学习笔记)(转)
1.游标是啥玩意?
简单的说:游标(cursor)就是游动的标识,啥意思呢,通俗的这么说,一条sql取出对应n条结果资源的接口/句柄,就是游标,沿着游标可以一次取出一行。我给大家准备一张图:

2.怎么使用游标?
//1.声明/定义一个游标
declare 声明;declare 游标名 cursor for select_statement;
//2.打开一个游标
open 打开;open 游标名
//3.取值
fetch 取值;fetch 游标名 into var1,var2[,...]
//4.关闭一个游标
close 关闭;close 游标名;
3.游标实战
未使用游标:
create procedure p1()
begin
select * from category;
end$
call p1$
执行结果:

使用游标:
/**
注释
*/
create procedure p2()
begin
//一下定义的三个变量用于将fetch取值出来的值放到对应的变量中
declare row_cat_id int;
declare row_cat_name int;
declare row_parent_id int;
//定义游标
declare getcategory cursor for select cat_id,cat_name,parent_id from category;
//打开游标
open getcategory;
//取值
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
//关闭游标
close getcategory;
end$
/**
未注释
*/
create procedure p2()
begin
declare row_cat_id int;
declare row_cat_name varchar(90);
declare row_parent_id int;
declare getcategory cursor for select cat_id,cat_name,parent_id from category;
open getcategory;
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
close getcategory;
end$
//执行的时候你会发现是0行,这时因为我们将查询出的结果赋给了变量,我们有没有对赋值后的变量进行查询显示。所以是0行。因此,我们要重新改进。
call p2()$
执行结果为:

//改进
//删除游标重新执行
drop procedure p2$
create procedure p2()
begin
declare row_cat_id int;
declare row_cat_name varchar(90);
declare row_parent_id int;
declare getcategory cursor for select cat_id,cat_name,parent_id from category;
open getcategory;
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
select row_cat_id,row_cat_name,row_parent_id;
close getcategory;
end$
call p2()$
执行结果如下:

这时候你会发现我们只得到了一个查询结果,这时为什么呢?这时因为控制权在我们这里,我愿意取一行就一行,愿意取两行就两行。因此,我在把刚才的动作变一下。
create procedure p3()
begin
declare row_cat_id int;
declare row_cat_name varchar(90);
declare row_parent_id int;
declare getcategory cursor for select cat_id,cat_name,parent_id from category;
open getcategory;
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
select row_cat_id,row_cat_name,row_parent_id;
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
select row_cat_id,row_cat_name,row_parent_id;
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
select row_cat_id,row_cat_name,row_parent_id;
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
select row_cat_id,row_cat_name,row_parent_id;
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
select row_cat_id,row_cat_name,row_parent_id;
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
select row_cat_id,row_cat_name,row_parent_id;
close getcategory;
end$
我fetch六次,查询五次,这时候我们会得到什么呢?试一下嘛!
call p4()$
执行结果如下:

提示:发现什么了吗?相同的语句,我们每取一次就往后游一次,有几次就游几次,直到你把游完所有标识,这时候系统就会报【02000】这个错误,告诉我们游标已经走完了。我们这里游了六次,因此会打印前六条记录。
所以啊,我们如何循环游标来取出所有行?
思路:
1.计算所有行select count(*)
create procedure p4()
begin
declare row_cat_id int;
declare row_cat_name varchar(90);
declare row_parent_id int;
declare cnt int default 0;//定义总行数
declare i int default 0;
declare getcategory cursor for select cat_id,cat_name,parent_id from category;
select count(*) into cnt from category;//计算得出的总行数查询后赋给cnt变量
open getcategory;
repeat
set i:=i+1;
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
select row_cat_id,row_cat_name,row_parent_id;
until i>=cnt end repeat;
close getcategory;
end$
call p4()$
执行结果为:

由此可见已经一条条得到表中结果,再次强调游标在此处的意义在于它把取出每一行的权利交给了你,你可以在每取出这一行的repeat中再做其他判断。
2.给游标定义一个越界的标识
//在mysql游标(cursor)中,可以定义continue handler来操作一个越界标识,使用语法:declare continue handler for NOT FOUND statemet(当没数据的时候要执行的语句)
//这句话的意思是说,我要声明一个句柄事件,你往后取,一旦发生NOT FOUND 事件就会出发set ergodic:=0这个语句
create procedure p5()
begin
declare row_cat_id int;
declare row_cat_name varchar(90);
declare row_parent_id int;
declare ergodic int default 1;//声明一个变量表明还有数据可遍历
declare getcategory cursor for select cat_id,cat_name,parent_id from category;
declare continue handler for NOT FOUND set ergodic:=0;
open getcategory;
repeat
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
select row_cat_id,row_cat_name,row_parent_id;
until ergodic=0 end repeat;
close getcategory;
end$
call p5()$
执行结果为:

发现问题没有?为啥第最后一个查了两次?这是什么原因?我们不妨来分析一下我们写的语句:

既然问题已经分析出来后,我们如何处理这个问题呢?
解决方案:声明处理的hanlder不再是continue,而是exit即可达到目的。即:declare exit handler for NOT FOUND set ergodic:=0;
//exit与continue的区别是:exit触发后,后面的语句不再执行,而continue还需要继续执行。
注意:除了这exit与continue两种方式外,还有一种方式就是undo handler。
//采用undo handler方式触发后,前面的语句直接撤销。【但目前好像这种方式,mysql还不支持】
create procedure p6()
begin
declare row_cat_id int;
declare row_cat_name varchar(90);
declare row_parent_id int;
declare ergodic int default 1;
declare getcategory cursor for select cat_id,cat_name,parent_id from category;
declare exit handler for NOT FOUND set ergodic:=0;
open getcategory;
repeat
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
select row_cat_id,row_cat_name,row_parent_id;
until ergodic=0 end repeat;
close getcategory;
end$
call p6()$
执行结果为:

由此,问题解决。
题外话:如果我们还是使用continue的方式去实现不重复的话,我们应该怎么做呢?这时候我们可以在我们代码逻辑上处理这种问题,我们先来分析一下代码:
提示:
你有没有考虑过,你第一次fetch取值的时候会不会存在没有数据(值为空)的情况,因此我们可以先手动的fetch一行出来,紧接着repeat下面的数据。
create procedure p7()
begin
declare row_cat_id int;
declare row_cat_name varchar(90);
declare row_parent_id int;
declare ergodic int default 1;
declare getcategory cursor for select cat_id,cat_name,parent_id from category;
declare continue handler for NOT FOUND set ergodic:=0;
open getcategory;
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
repeat
select row_cat_id,row_cat_name,row_parent_id;
fetch getcategory into row_cat_id,row_cat_name,row_parent_id;
until ergodic=0 end repeat;
close getcategory;
end$
call p7()$
执行结果为:

附件:
测试数据库与数据表:
create table category (
cat_id smallint unsigned auto_increment primary key,
cat_name varchar(90) not null default '',
parent_id smallint unsigned
)engine myisam charset utf8;
INSERT INTO `category` VALUES
(1,'手机类型',0),
(2,'CDMA手机',1),
(3,'GSM手机',1),
(4,'3G手机',1),
(5,'双模手机',1),
(6,'手机配件',0),
(7,'充电器',6),
(8,'耳机',6),
(9,'电池',6),
(11,'读卡器和内存卡',6),
(12,'充值卡',0),
(13,'小灵通/固话充值卡',12),
(14,'移动手机充值卡',12),
(15,'联通手机充值卡',12);
mysql中游标的使用案例详解(学习笔记)(转)的更多相关文章
- mysql中游标的使用案例详解(学习笔记)
1.游标是啥玩意?简单的说:游标(cursor)就是游动的标识,啥意思呢,通俗的这么说,一条sql取出对应n条结果资源的接口/句柄,就是游标,沿着游标可以一次取出一行.我给大家准备一张图: 2.怎么使 ...
- 孙鑫视频VC++深入详解学习笔记
孙鑫视频VC++深入详解学习笔记 VC++深入详解学习笔记 Lesson1: Windows程序运行原理及程序编写流程 Lesson2: 掌握C++基本语法 Lesson3: MFC框架程序剖析 Le ...
- TCP/IP详解学习笔记
TCP/IP详解学习笔记(1)-基本概念 TCP/IP详解学习笔记(2)-数据链路层 TCP/IP详解学习笔记(3)-IP协议,ARP协议,RARP协议 TCP/IP详解学习笔记(4)-ICMP协议, ...
- TCP/IP详解学习笔记 这位仁兄写得太好了
TCP/IP详解学习笔记(1)-基本概念 为什么会有TCP/IP协议 在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣 ...
- TCP/IP详解学习笔记- 概述
TCP/IP详解学习笔记(1)-- 概述1.TCP/IP的分层结构 网络协议通常分不同层次进行开发,每一层分别负责不同的同信功能.TCP/IP通常被认为是一个四层协议系统. 如图所 ...
- TCP-IP详解学习笔记2
TCP-IP详解学习笔记2 链路层 链路层的目的是为IP模块发送和接收IP数据报: TCP/IP支持多种不同的链路层,依赖于使用网络硬件类型:有线局域网(以太网,城域网(MAN),有线语音网络).无线 ...
- TCP-IP详解学习笔记1
TCP-IP详解学习笔记1 网关可以在互不相关的网络之间提供翻译功能: 体系结构: 协议和物理实现,实际上是一组设计决策. TCP/IP协议族允许计算机,智能手机,嵌入式设备之间通信: TCP/IP是 ...
- TCP/IP详解学习笔记 这位仁兄写得太好了.(转载)
TCP/IP详解学习笔记 这位仁兄写得太好了 TCP/IP详解学习笔记 这位仁兄写得太好了. http://blog.csdn.net/goodboy1881/category/20444 ...
- 【转】TCP/IP详解学习笔记(二)
TCP/IP详解学习笔记(5)-IP选路,动态选路,和一些细节 1.静态IP选路 1.1.一个简单的路由表 选路是IP层最重要的一个功能之一.前面的部分已经简单的讲过路由器是通过何种规则来根据IP数据 ...
随机推荐
- 【BZOJ1064】[NOI2008] 假面舞会(图上DFS)
点此看题面 大致题意:有\(k\)种面具(\(k\)是一个未知数且\(k≥3\),每种面具可能有多个),已知戴第\(i\)种面具的人能看到第\(i+1\)种面具上的编号,特殊的,戴第\(k\)种面具的 ...
- python_41_with语句
#为了避免打开文件后忘记关闭,可以通过管理上下文,即:with open('log','r') as f: # 如此方式,当with代码块执行完毕时,内部会自动关闭并释放文件资源. with open ...
- frombuffer的用法
函数原型为:numpy.ma.frombuffer(buffer, dtype=float, count=-1, offset=0) import numpy s = 'hello world' pr ...
- java实现微信扫一扫详解
java实现微信扫一扫详解 一.微信JS-SDK参数配置及查找 JS安全域名配置(查找:微信公众号里-公众号设置-功能设置页) 注:1.安全域名外网必须可以访问的到 2.域名不能有下划线 3.要将 ...
- 解决Mycat对自增表不支持(第一种已测试通过)
表 INSERT INTO news_class (`class_id`,`class_name`) VALUES (next VALUE FOR MYCATSEQ_GLOBAL,'1'); sequ ...
- d3.js--01
D3 的全称是(Data-Driven Documents),顾名思义可以知道是一个被数据驱动的文档.听名字有点抽象,说简单一点,其实就是一个 JavaScript 的函数库,使用它主要是用来做数据可 ...
- Duizi and Shunzi HDU - 6188 (贪心)2017 广西ACM/ICPC
Duizi and Shunzi Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- PAT 乙级 1024
题目 题目地址:PAT 乙级 1024 题解 模拟题,重点需要考虑到各种不同情况:简单来说一下: 因为输入格式固定,所以把不同的部分分别存储和处理可以在很大程度上简化运算:其中需要考虑最多的就是小数部 ...
- SpingBoot之多Profile文件
1.我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml默认使用application.properties的配置: 在我们的项目开发.测 ...
- Thinkphp5封装上传图片
<?php namespace app\api\controller; use think\Controller; use think\Db; class Plus extends Base{ ...