mysql 在函数里创建游标_Mysql系列第十八讲 游标详解

本文详细介绍了MySQL中游标的概念、作用、使用步骤,并通过实例展示了如何在函数中创建游标进行数据处理。游标允许在存储过程和函数中逐行遍历查询结果,提供了一种处理数据的有效方法。文章还给出了单游标和嵌套游标的示例,帮助读者理解游标的使用流程。
摘要由CSDN通过智能技术生成

准备数据

创建库: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);123456789101112131415161718

游标定义

http://ask.baikezh.com/

游标(Cursor)是处理数据的一种方法,为了查看或者处理结果集中的数据,游标提供了在结果集中一次一行遍历数据的能力。

游标只能在存储过程和函数中使用。

游标的作用

如sql:

select a,b from test1;1

上面这个查询返回了test1中的数据,如果我们想对这些数据进行遍历处理,此时我们就可以使用游标来进行操作。

游标相当于一个指针,这个指针指向select的第一行数据,可以通过移动指针来遍历后面的数据。

游标的使用步骤

声明游标:这个过程只是创建了一个游标,需要指定这个游标需要遍历的select查询,声明游标时并不会去执行这个sql。

打开游标:打开游标的时候,会执行游标对应的select语句。

遍历数据:使用游标循环遍历select结果中每一行数据,然后进行处理。

关闭游标:游标使用完之后一定要关闭。

游标语法

声明游标

http://dxb.myzx.cn/grandmal/

DECLARE 游标名称 CURSOR FOR 查询语句;1

一个begin end中只能声明一个游标。

打开游标

open 游标名称;1

遍历游标

fetch 游标名称 into 变量列表;1

取出当前行的结果,将结果放在对应的变量中,并将游标指针指向下一行的数据。

当调用fetch的时候,会获取当前行的数据,如果当前行无数据,会引发mysql内部的NOT FOUND错误。

关闭游标

http://zzdxb.baikezh.com/

close 游标名称;1

游标使用完毕之后一定要关闭。

单游标示例

写一个函数,计算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 ;123456789101112131415161718192021222324252627282930313233343536373839404142

上面语句执行过程中可能有问题,解决方式如下。

http://ask.baikezh.com/changchun/

错误信息: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:

执行:

http://zzdxb.baikezh.com/xinyang/

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)123456789101112131415161718192021222324252627282930313233

游标过程详解

以上面的示例代码为例,咱们来看一下游标的详细执行过程。

游标中有个指针,当打开游标的时候,才会执行游标对应的select语句,这个指针会指向select结果中第一行记录。

当调用fetch 游标名称时,会获取当前行的数据,如果当前行无数据,会触发NOT FOUND异常。

当触发NOT FOUND异常的时候,我们可以使用一个变量来标记一下,如下代码:

DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done=TRUE;1

当游标无数据触发NOT FOUND异常的时候,将变量v_down的值置为TURE,循环中就可以通过v_down的值控制循环的退出。

http://dxb.myzx.cn/harm/

如果当前行有数据,则将当前行数据存到对应的变量中,并将游标指针指向下一行数据,如下语句:

fetch 游标名称 into 变量列表;1

嵌套游标

写个存储过程,遍历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 ;12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758

见效果:

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)123456789101112131415161718192021222324

成功插入了9条数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值