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中游标的使用案例详解(学习笔记)的更多相关文章

  1. mysql中游标的使用案例详解(学习笔记)(转)

    1.游标是啥玩意?简单的说:游标(cursor)就是游动的标识,啥意思呢,通俗的这么说,一条sql取出对应n条结果资源的接口/句柄,就是游标,沿着游标可以一次取出一行.我给大家准备一张图: 2.怎么使 ...

  2. 孙鑫视频VC++深入详解学习笔记

    孙鑫视频VC++深入详解学习笔记 VC++深入详解学习笔记 Lesson1: Windows程序运行原理及程序编写流程 Lesson2: 掌握C++基本语法 Lesson3: MFC框架程序剖析 Le ...

  3. TCP/IP详解学习笔记

    TCP/IP详解学习笔记(1)-基本概念 TCP/IP详解学习笔记(2)-数据链路层 TCP/IP详解学习笔记(3)-IP协议,ARP协议,RARP协议 TCP/IP详解学习笔记(4)-ICMP协议, ...

  4. TCP/IP详解学习笔记 这位仁兄写得太好了

      TCP/IP详解学习笔记(1)-基本概念 为什么会有TCP/IP协议 在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣 ...

  5. TCP/IP详解学习笔记- 概述

    TCP/IP详解学习笔记(1)-- 概述1.TCP/IP的分层结构      网络协议通常分不同层次进行开发,每一层分别负责不同的同信功能.TCP/IP通常被认为是一个四层协议系统.      如图所 ...

  6. TCP-IP详解学习笔记2

    TCP-IP详解学习笔记2 链路层 链路层的目的是为IP模块发送和接收IP数据报: TCP/IP支持多种不同的链路层,依赖于使用网络硬件类型:有线局域网(以太网,城域网(MAN),有线语音网络).无线 ...

  7. TCP-IP详解学习笔记1

    TCP-IP详解学习笔记1 网关可以在互不相关的网络之间提供翻译功能: 体系结构: 协议和物理实现,实际上是一组设计决策. TCP/IP协议族允许计算机,智能手机,嵌入式设备之间通信: TCP/IP是 ...

  8. TCP/IP详解学习笔记 这位仁兄写得太好了.(转载)

    TCP/IP详解学习笔记   这位仁兄写得太好了   TCP/IP详解学习笔记   这位仁兄写得太好了. http://blog.csdn.net/goodboy1881/category/20444 ...

  9. 【转】TCP/IP详解学习笔记(二)

    TCP/IP详解学习笔记(5)-IP选路,动态选路,和一些细节 1.静态IP选路 1.1.一个简单的路由表 选路是IP层最重要的一个功能之一.前面的部分已经简单的讲过路由器是通过何种规则来根据IP数据 ...

随机推荐

  1. 过滤字符串html标签方法

    过滤字符串html标签方法,如果输入的过滤标签为“*”,那么给字符串加上p标签 public static string noTagHtml(string str, string tagname) { ...

  2. zf-启动项目报错Server 127.0.0.1 has no instance named dlx 解决办法

    由于百度出来的看不明白,于是我就在群里问,吴善如经理说:你这个问题我上次给李宽看过,用端口连,把instance去掉 然后我去掉之后 项目过程能够成功运行了,原来是这样

  3. 51nod 区间中第K大的数

    区间中第K大的数 基准时间限制:1 秒 空间限制:131072 KB  一个长度为N的整数序列,编号0 - N - 1.进行Q次查询,查询编号i至j的所有数中,第K大的数是多少. 例如: 1 7 6 ...

  4. 洛谷 U4704 函数

    设gcd(a,b)为a和b的最大公约数,xor(a,b)为a异或b的结果. 题目描述 kkk总是把gcd写成xor.今天数学考试恰好出到了gcd(a,b)=?这样的题目,但是kkk全部理解成了xor( ...

  5. (转)初识suse——linux

    Linux这种系统很奇怪,差不多每种不同的版本,它所使用的安装等一些重要命令皆有所变化.假若,你要熟练掌握一种OS,那么如果安装软件/应用,那是入门的第一步.   安装命令中: RedHat.Cent ...

  6. 微信小程序登陆流程

    #1:session_key和openId是什么?session_key 官方说明为:session_key是微信服务器生成的针对用户数据进行加密签名的密钥session_key的用途(1)对wx.g ...

  7. GPRS优点介绍及GPRS上网相关知识(转)

    源:http://blog.chinaunix.net/uid-20745340-id-1878732.html 单片机微控制器以其体积小.功耗低.使用方便等特点,广泛应用于各种工业.民用的嵌入式系统 ...

  8. Padding和父子继承宽高之间的关系

    1.父子之间宽高的继承关系 父亲有一个宽高,儿子若不设定宽高会继承,继承宽的100%,高度靠自己内容撑开. 2.padding对儿子宽的影响 看代码: <style> .father{ w ...

  9. hadoop第一篇

    1 hadoop整体架构 2 各组件关系 hdfs只是一个存储空间,他的完整名字是分布式文件系统.有名可知他的作用了. hbase是一个内存数据库,简单点说hbase把表啊什么的存在hdfs上.

  10. iReport使用教程

    http://www.blogjava.net/keweibo/articles/239492.html 原创出处 http://blog.163.com/liushuo216@126/blog/st ...