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. 【洛谷4884】多少个1?(BSGS)

    点此看题面 大致题意: 求满足\(个111...111(N\text{个}1)\equiv K(mod\ m)\)的最小\(N\). 题目来源 这题是洛谷某次极不良心的月赛的\(T1\),当时不会\( ...

  2. window下部署yapi

    YApi 是一个可本地部署的.打通前后端及QA的.可视化的接口管理平台. 环境要求 nodejs(尽量最新版本) mongodb(尽量最新版本) 1.安装node https://www.runoob ...

  3. Javascript笔记部分

    写入HTML输出 document.write(“<h1>”); 改变HTML内容 x = document.getElementById(“demo”) //查找元素 后面可以.valu ...

  4. CURLOPT_PROGRESSFUNCTION

    Author:李强(李祥祥) Date   :2012-12-15 17:26 LIBCURL官方网站都没有说清楚道明白进度函数的参数的作用,这点我感觉文档很片面,经总结如下: size_t CUpl ...

  5. HH的项链题解(离线思想+链表+树状数组)

    本人第一篇博客重磅推出!!! 希望各位朋友以后多多捧场也多给写意见(我个人喜欢把题解写得啰嗦一点,因为这样方便理解,各位巨佬勿喷) 来讲一道提高+/省选-的骚题:HH的项链(这个HH你理解成皇后呵呵哈 ...

  6. ELFhash - 优秀的字符串哈希算法

    ELFhash - 优秀的字符串哈希算法 2016年10月29日 22:12:37 阅读数:6440更多 个人分类: 算法杂论算法精讲数据结构 所属专栏: 算法与数据结构   版权声明:本文为博主原创 ...

  7. 详解三种java实现多线程的方式

    java中实现多线程的方法有两种:继承Thread类和实现runnable接口. 1.继承Thread类,重写父类run()方法 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...

  8. 该网页无法正常运作 目前无法处理此请求HTTP ERROR 500?

    由于php.ini配置文件中错误显示关闭导致. 将下值由Off 变更为 On display_errors = On display_startup_errors = On

  9. C++ lambda 表达式 简介

    自己根据对lambda表达式的理解,做了一套ppt简单介绍

  10. nginx下根据指定路由重定向

    前言: 最近在搭建vue后台,后端接口是PHP写的,线上构建好之后,需要请求其他域名下的接口,开发环境已经使用proxytable解决了接口问题,为了开发和生成的代码一致, 编译后的代码,放在ngin ...