Mysql高手系列 - 第19篇:mysql游标详解,此技能可用于救火
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能。
这是Mysql系列第19篇。
环境:mysql5.7.25,cmd命令中进行演示。
代码中被[]包含的表示可选,|符号分开的表示可选其一。
需求背景
当我们需要对一个select的查询结果进行遍历处理的时候,如何实现呢?
此时我们需要使用游标,通过游标的方式来遍历select查询的结果集,然后对每行数据进行处理。
本篇内容
- 游标定义
- 游标作用
- 游标使用步骤
- 游标执行过程详解
- 单游标示例
- 嵌套游标示例
准备数据
创建库:javacode2018
创建表:test1、test2、test3
/*建库javacode2018*/
drop database if exists javacode2018;
create database javacode2018;
/*切换到javacode2018库*/
use javacode2018;
DROP TABLE IF EXISTS test1;
CREATE TABLE test1(a int,b int);
INSERT INTO test1 VALUES (1,2),(3,4),(5,6);
DROP TABLE IF EXISTS test2;
CREATE TABLE test2(a int);
INSERT INTO test2 VALUES (100),(200),(300);
DROP TABLE IF EXISTS test3;
CREATE TABLE test3(b int);
INSERT INTO test3 VALUES (400),(500),(600);
游标定义
游标(Cursor)是处理数据的一种方法,为了查看或者处理结果集中的数据,游标提供了在结果集中一次一行遍历数据的能力。
游标只能在存储过程和函数中使用。
游标的作用
如sql:
select a,b from test1;
上面这个查询返回了test1中的数据,如果我们想对这些数据进行遍历处理,此时我们就可以使用游标来进行操作。
游标相当于一个指针,这个指针指向select的第一行数据,可以通过移动指针来遍历后面的数据。
游标的使用步骤
声明游标:这个过程只是创建了一个游标,需要指定这个游标需要遍历的select查询,声明游标时并不会去执行这个sql。
打开游标:打开游标的时候,会执行游标对应的select语句。
遍历数据:使用游标循环遍历select结果中每一行数据,然后进行处理。
关闭游标:游标使用完之后一定要关闭。
游标语法
声明游标
DECLARE 游标名称 CURSOR FOR 查询语句;
一个begin end中只能声明一个游标。
打开游标
open 游标名称;
遍历游标
fetch 游标名称 into 变量列表;
取出当前行的结果,将结果放在对应的变量中,并将游标指针指向下一行的数据。
当调用fetch的时候,会获取当前行的数据,如果当前行无数据,会引发mysql内部的
NOT FOUND错误。
关闭游标
close 游标名称;
游标使用完毕之后一定要关闭。
单游标示例
写一个函数,计算test1表中a、b字段所有的和。
创建函数:
/*删除函数*/
DROP FUNCTION IF EXISTS fun1;
/*声明结束符为$*/
DELIMITER $
/*创建函数*/
CREATE FUNCTION fun1(v_max_a int)
RETURNS int
BEGIN
/*用于保存结果*/
DECLARE v_total int DEFAULT 0;
/*创建一个变量,用来保存当前行中a的值*/
DECLARE v_a int DEFAULT 0;
/*创建一个变量,用来保存当前行中b的值*/
DECLARE v_b int DEFAULT 0;
/*创建游标结束标志变量*/
DECLARE v_done int DEFAULT FALSE;
/*创建游标*/
DECLARE cur_test1 CURSOR FOR SELECT a,b from test1 where a<=v_max_a;
/*设置游标结束时v_done的值为true,可以v_done来判断游标是否结束了*/
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done=TRUE;
/*设置v_total初始值*/
SET v_total = 0;
/*打开游标*/
OPEN cur_test1;
/*使用Loop循环遍历游标*/
a:LOOP
/*先获取当前行的数据,然后将当前行的数据放入v_a,v_b中,如果当前行无数据,v_done会被置为true*/
FETCH cur_test1 INTO v_a, v_b;
/*通过v_done来判断游标是否结束了,退出循环*/
if v_done THEN
LEAVE a;
END IF;
/*对v_total值累加处理*/
SET v_total = v_total + v_a + v_b;
END LOOP;
/*关闭游标*/
CLOSE cur_test1;
/*返回结果*/
RETURN v_total;
END $
/*结束符置为;*/
DELIMITER ;
上面语句执行过程中可能有问题,解决方式如下。
错误信息:Mysql 创建函数出现This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA
This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary
mysql的设置默认是不允许创建函数
解决办法1:
执行:
SET GLOBAL log_bin_trust_function_creators = 1;
不过 重启了 就失效了
注意: 有主从复制的时候 从机必须要设置 不然会导致主从同步失败
解决办法2:
在my.cnf里面设置
log-bin-trust-function-creators=1
不过这个需要重启服务
见效果:
mysql> SELECT a,b FROM test1;
+------+------+
| a | b |
+------+------+
| 1 | 2 |
| 3 | 4 |
| 5 | 6 |
+------+------+
3 rows in set (0.00 sec)
mysql> SELECT fun1(1);
+---------+
| fun1(1) |
+---------+
| 3 |
+---------+
1 row in set (0.00 sec)
mysql> SELECT fun1(2);
+---------+
| fun1(2) |
+---------+
| 3 |
+---------+
1 row in set (0.00 sec)
mysql> SELECT fun1(3);
+---------+
| fun1(3) |
+---------+
| 10 |
+---------+
1 row in set (0.00 sec)
游标过程详解
以上面的示例代码为例,咱们来看一下游标的详细执行过程。
游标中有个指针,当打开游标的时候,才会执行游标对应的select语句,这个指针会指向select结果中第一行记录。
当调用fetch 游标名称时,会获取当前行的数据,如果当前行无数据,会触发NOT FOUND异常。
当触发NOT FOUND异常的时候,我们可以使用一个变量来标记一下,如下代码:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done=TRUE;
当游标无数据触发NOT FOUND异常的时候,将变量v_down的值置为TURE,循环中就可以通过v_down的值控制循环的退出。
如果当前行有数据,则将当前行数据存到对应的变量中,并将游标指针指向下一行数据,如下语句:
fetch 游标名称 into 变量列表;
嵌套游标
写个存储过程,遍历test2、test3,将test2中的a字段和test3中的b字段任意组合,插入到test1表中。
创建存储过程:
/*删除存储过程*/
DROP PROCEDURE IF EXISTS proc1;
/*声明结束符为$*/
DELIMITER $
/*创建存储过程*/
CREATE PROCEDURE proc1()
BEGIN
/*创建一个变量,用来保存当前行中a的值*/
DECLARE v_a int DEFAULT 0;
/*创建游标结束标志变量*/
DECLARE v_done1 int DEFAULT FALSE;
/*创建游标*/
DECLARE cur_test1 CURSOR FOR SELECT a FROM test2;
/*设置游标结束时v_done1的值为true,可以v_done1来判断游标cur_test1是否结束了*/
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done1=TRUE;
/*打开游标*/
OPEN cur_test1;
/*使用Loop循环遍历游标*/
a:LOOP
FETCH cur_test1 INTO v_a;
/*通过v_done1来判断游标是否结束了,退出循环*/
if v_done1 THEN
LEAVE a;
END IF;
BEGIN
/*创建一个变量,用来保存当前行中b的值*/
DECLARE v_b int DEFAULT 0;
/*创建游标结束标志变量*/
DECLARE v_done2 int DEFAULT FALSE;
/*创建游标*/
DECLARE cur_test2 CURSOR FOR SELECT b FROM test3;
/*设置游标结束时v_done1的值为true,可以v_done1来判断游标cur_test2是否结束了*/
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done2=TRUE;
/*打开游标*/
OPEN cur_test2;
/*使用Loop循环遍历游标*/
b:LOOP
FETCH cur_test2 INTO v_b;
/*通过v_done1来判断游标是否结束了,退出循环*/
if v_done2 THEN
LEAVE b;
END IF;
/*将v_a、v_b插入test1表中*/
INSERT INTO test1 VALUES (v_a,v_b);
END LOOP b;
/*关闭cur_test2游标*/
CLOSE cur_test2;
END;
END LOOP;
/*关闭游标cur_test1*/
CLOSE cur_test1;
END $
/*结束符置为;*/
DELIMITER ;
见效果:
mysql> DELETE FROM test1;
Query OK, 9 rows affected (0.00 sec)
mysql> SELECT * FROM test1;
Empty set (0.00 sec)
mysql> CALL proc1();
Query OK, 0 rows affected (0.02 sec)
mysql> SELECT * from test1;
+------+------+
| a | b |
+------+------+
| 100 | 400 |
| 100 | 500 |
| 100 | 600 |
| 200 | 400 |
| 200 | 500 |
| 200 | 600 |
| 300 | 400 |
| 300 | 500 |
| 300 | 600 |
+------+------+
9 rows in set (0.00 sec)
成功插入了9条数据。
总结
- 游标用来对查询结果进行遍历处理
- 游标的使用过程:声明游标、打开游标、遍历游标、关闭游标
- 游标只能在存储过程和函数中使用
- 一个begin end中只能声明一个游标
- 掌握单个游标及嵌套游标的使用
- 大家下去了多练习一下,熟练掌握游标的使用
Mysql系列目录
- 第1篇:mysql基础知识
- 第2篇:详解mysql数据类型(重点)
- 第3篇:管理员必备技能(必须掌握)
- 第4篇:DDL常见操作
- 第5篇:DML操作汇总(insert,update,delete)
- 第6篇:select查询基础篇
- 第7篇:玩转select条件查询,避免采坑
- 第8篇:详解排序和分页(order by & limit)
- 第9篇:分组查询详解(group by & having)
- 第10篇:常用的几十个函数详解
- 第11篇:深入了解连接查询及原理
- 第12篇:子查询
- 第13篇:细说NULL导致的神坑,让人防不胜防
- 第14篇:详解事务
- 第15篇:详解视图
- 第16篇:变量详解
- 第17篇:存储过程&自定义函数详解
- 第18篇:流程控制语句
- 第19篇:游标详解
- 第20篇:异常捕获及处理详解
- 第21篇:什么是索引?
mysql系列大概有20多篇,喜欢的请关注一下,欢迎大家加我微信itsoku或者留言交流mysql相关技术!

Mysql高手系列 - 第19篇:mysql游标详解,此技能可用于救火的更多相关文章
- Mysql高手系列 - 第21篇:什么是索引?
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第21篇. 本文开始连续3篇详解mysql索引: 第1篇来说说什么是索引? 第2篇详解Mysql中 ...
- Mysql高手系列 - 第18篇:mysql流程控制语句详解(高手进阶)
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第18篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符 ...
- Mysql高手系列 - 第20篇:异常捕获及处理详解(实战经验)
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第20篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符 ...
- Mysql高手系列 - 第22篇:深入理解mysql索引原理,连载中
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 这是Mysql系列第22篇. 背景 使用mys ...
- Mysql高手系列 - 第24篇:如何正确的使用索引?【高手进阶】
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 这是Mysql系列第24篇. 学习索引,主要是 ...
- Mysql高手系列 - 第27篇:mysql如何确保数据不丢失的?我们借鉴这种设计思想实现热点账户高并发设计及跨库转账问题
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 这是Mysql系列第27篇. 本篇文章我们先来 ...
- Mysql高手系列 - 第26篇:聊聊如何使用mysql实现分布式锁
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 这是Mysql系列第26篇. 本篇我们使用my ...
- Mysql高手系列 - 第9篇:详解分组查询,mysql分组有大坑!
这是Mysql系列第9篇. 环境:mysql5.7.25,cmd命令中进行演示. 本篇内容 分组查询语法 聚合函数 单字段分组 多字段分组 分组前筛选数据 分组后筛选数据 where和having的区 ...
- Mysql高手系列 - 第8篇:详解排序和分页(order by & limit),及存在的坑
这是Mysql系列第8篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符号分开的表示可选其一. 本章内容 详解排序查询 详解limit limit存在的坑 分 ...
随机推荐
- HDU-2089不要62-暴力或数位DP入门
不要62 题意:给定区间,求在这个区间中有多少个数字,不包含4且不包含62: 这道题作为数位DP的入门题: 暴力也是可以过 #include<cstdio> #include <io ...
- 题解 bzoj 2151 种树
题意 传送门 手写堆大法好啊,题解貌似没有结构体堆的做法,思路有些像配对堆,关于配对堆请自行百度,因为本蒟蒻不会.. 以下是蒟蒻的做法:建立一个大根堆a维护最大价值里面存入它的编号以及价值.听说配对堆 ...
- HDU 1223 还是畅通工程(最小生成树prim模板)
一个很简单的prim模板,但虽然是模板,但也是最基础的,也要脱离模板熟练打出来 后期会更新kruskal写法 #include<iostream> #include<cstdio&g ...
- 设置普通用户输入sudo,免密进入root账户
满足给开发用户开权限,赋予sudo权限.又不让其输入密码的方式: 方式一: 开始系统内部的wheel用户组, 在/etc/suoers 中编辑配置文件如下: %wheel ALL=(ALL) NOPA ...
- 编写一个函数来找出所有不带歧义的函数名,也就是 那些只在一个模块里出现过的函数名(erlang)
erlang程序设计第八章练习题第二题: code:all_loaded()命令会返回一个由{Mod,File}对构成的列表,内含所有Erlang系统 载入的模块.使用内置函数Mod:module_i ...
- Docker 学习线路
起因 之前的几篇博客,需要一定的docker知识(虽然可以直接上手),但是对于没有docker基础的人来说是不知道为什么要这样做的. 我把之前学习docker的步骤整理出来,希望可以帮助更多的人去学习 ...
- EventBus 消息的线程切换模型与实现原理
一. 序 EventBus 是一个基于观察者模式的事件订阅/发布框架,利用 EventBus 可以在不同模块之间,实现低耦合的消息通信. EventBus 因为其使用简单且稳定,被广泛应用在一些生产项 ...
- hadoop snapshot 备份恢复 .
1.允许创建快照 首先,在你想要进行备份的文件夹下面 执行命令,允许该文件夹创建快照 hdfs dfsadmin -allowSnapshot <path> 例如:hdfs dfsadmi ...
- mysql解压版服务启动方式
使用mysql解压版,在不安装为windows服务时,使用下面的方式启动. 1.打开命令行,首先进入mysql解压目录的bin目录下 d:\mysql\bin 2.输入mysqld --console ...
- Java面试-容器的遍历
当我们用增强for循环遍历非并发容器(HashMap.ArrayList等),如果修改其结构,会抛出异常ConcurrentModificationException,因此在阿里巴巴的Java规范中有 ...