MySQL存储过程实现双重循环遍历结果集的方法
通过MySQL存储过程实现双重for循环遍历结果集,使用游标获取外层结果集,在循环内根据外层变量执行内层SQL更新操作。该方法适用于按规则更新同类型数据,核心是将外层查询的oid作为参数代入内层更新语句。
需求背景与实现思路
在实际开发中,我遇到了一个需要遍历结果集并进行复杂更新的场景:对以下类型的数据集合进行计算更新。

更新规则为:当type为c时,其currentValue = (type为b的currentValue) / ((type为b的currentValue) + (type为a的currentValue)) * 100。
这类需求有多种解法。面对这个场景,我首先联想到双重for循环的思路:先查询第一个结果集(包含oid字段),然后遍历该结果集,将每个oid作为参数代入第二个SQL语句进行更新操作。
本文将采用定义MySQL存储过程的方式来实现对结果集的遍历,也就是通常所说的“双重for循环”模式。
使用的工具:Navicat。
数据准备如下:
DROP TABLE IF EXISTS `report_data`;CREATE TABLE `report_data` ( `id` int(255) NOT NULL, `oid` int(255) NOT NULL, `type` varchar(10) not NULL, `currentValue` double not NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `report_data` (`id`, `oid`, `type`, `currentValue`) VALUES (1, 1, 'a', 1);INSERT INTO `report_data` (`id`, `oid`, `type`, `currentValue`) VALUES (2, 1, 'b', 2);INSERT INTO `report_data` (`id`, `oid`, `type`, `currentValue`) VALUES (3, 1, 'c', 3);INSERT INTO `report_data` (`id`, `oid`, `type`, `currentValue`) VALUES (4, 1, 'd', 4);INSERT INTO `report_data` (`id`, `oid`, `type`, `currentValue`) VALUES (5, 2, 'a', 5);INSERT INTO `report_data` (`id`, `oid`, `type`, `currentValue`) VALUES (6, 2, 'b', 6);INSERT INTO `report_data` (`id`, `oid`, `type`, `currentValue`) VALUES (7, 2, 'c', 7);INSERT INTO `report_data` (`id`, `oid`, `type`, `currentValue`) VALUES (8, 2, 'd', 8);
如何遍历查询结果集
首先来看一个通用的存储过程模板,有助于后续理解具体实现:
CREATE PROCEDURE [存储过程名称()]BEGIN DECLARE s int DEFAULT 0; DECLARE [变量名 1 ] INT DEFAULT 0; DECLARE [变量名 2 ] VARCHAR ( 255 ); DECLARE [游标名] CURSOR FOR [包含结果集的 SQL ] DECLARE CONTINUE HANDLER FOR NOT FOUND SET s=1; OPEN [游标名]; FETCH [游标名] INTO [变量名 1 ],[变量名 2 ]; WHILE s <> 1 DO [你想操作的 SQL语句 ] FETCH [游标名] INTO [变量名 1 ],[变量名 2 ]; END WHILE;CLOSE [游标名];END;
下面逐部分进行详细解释:
(1)CREATE PROCEDURE [存储过程名称()] 表示创建一个存储过程。例如,如果我们将存储过程命名为processdata,则对应语句为 CREATE PROCEDURE processdata()。
(2)BEGIN 和 END 分别标识存储过程体的开始与结束。
(3)
DECLARE[变量名 1 ] INT DEFAULT 0;DECLARE[变量名 2 ] VARCHAR ( 255 );
这两行用于定义变量,目的是将查询结果集中的数据存放至变量中,以便后续进行二次操作。需要特别注意:变量名不能与结果集中的字段名重复,例如结果集中包含id和name,则变量最好命名为idTemp、nameTemp。同时,变量类型必须与字段类型对应。另外,DECLARE s int DEFAULT 0; 是定义循环控制变量,用于后续while循环的判断。
(4)
DECLARE [游标名] CURSOR FOR [包含结果集的 SQL ]
这行用于定义游标,游标中存放我们需要遍历的结果集SQL。例如:
DECLARE stu CURSOR FOR select id,name from student group by id;
这样第一个结果集就定义完成了,接下来就是遍历该结果集。
(5)DECLARE CONTINUE HANDLER FOR NOT FOUND SET s=1; 声明当游标遍历完所有数据后,将标志变量s的值设置为1,作为循环结束的条件。
(6)OPEN [游标名]; 打开游标,准备开始遍历。
(7)FETCH [游标名] INTO [变量名 1 ],[变量名 2 ]; 将游标当前指向行的数据依次赋值给对应的变量,顺序必须一一对应。例如:
FETCH stu INTO idTemp,nameTemp;
这里idTemp对应结果集中的id字段,nameTemp对应name字段。
(8)
WHILE s <> 1 DO....END WHILE;
这是while循环体,当s不等于1时持续执行循环内的操作。
(9)[你想操作的sql语句] 就是内部循环需要执行的具体操作,例如编写一个update语句:
update student set score='91' where id=idTemp and name = nameTemp;
该语句会引用上方游标获取到的id和name值,代入条件进行更新。
(10)FETCH [游标名] INTO [变量名 1 ],[变量名 2 ]; 在循环体内再次执行fetch,将游标指针向后移动,以便下一次循环读取下一行数据。
定义完成后,执行存储过程,在Navicat的函数列表中找到刚才定义的函数并执行即可。
实现具体需求
上面的模板已经清晰展示了整个流程,现在直接套用来解决本文开头提出的需求。
CREATE PROCEDURE processData()BEGINDECLARE s int DEFAULT 0;DECLARE oidTemp int DEFAULT 20;DECLARE report CURSOR FOR SELECT oid from report_data GROUP BY oid;DECLARE CONTINUE HANDLER FOR NOT FOUND SET s=1; open report; fetch report into oidTemp; while s<>1 do SET @fenzi= (SELECT currentValue from report_data WHERE type='b' and oid =oidTemp); set @fenmu= (SELECT currentValue from report_data WHERE type='a' and oid =oidTemp) + (SELECT currentValue from report_data WHERE type='b' and oid =oidTemp); set @result = @fenzi/@fenmu *100; update report_data set currentvalue = @result WHERE oid =oidTemp and type='c'; fetch report into oidTemp; end while; close report;END;
执行后的结果如下图所示:

总结
以上就是通过MySQL存储过程实现双重for循环遍历结果集的完整示例。核心思路为:先利用游标获取外层结果集,然后在循环体内根据外层变量执行内层SQL操作。掌握这个通用模板后,类似的数据更新需求都可以快速套用并高效实现。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
自增主键值从何而来?深入理解原理,告别只会auto_increment
KingbaseES推荐使用serial、bigserial、显式sequence或identity列实现自增主键。serial创建integer并关联序列,bigserial对应bigint;显式sequence可自定义起始值等参数;identity有generatedbydefault(允许指定值)与always(禁止)两种模式。
Linux下瀚高数据库授权文件过期及替换解决方案
在银河麒麟系统下,瀚高数据库hgdb-4 5试用授权20天到期后需替换正式授权文件。正确操作:停止服务,备份旧文件,将授权文件复制到 opt highgo hgdb-4 5 etc lic 并命名为hgdb lic,设置权限600和属主highgo:highgo,再启动服务。禁止直接修改data目录下的license info文件。
Oracle BLOB实时同步的5大技术挑战与难点解析
OracleBLOB实时同步面临分片组装、多列隔离、长事务跨窗口、事务回滚及大对象资源控制等技术挑战,必须在日志中精确还原完整字段值,才能保证源端与目标端数据完全一致,这对同步系统的稳健性提出了高要求。
MySQL禁用redo日志导致全备失败
MySQL全量备份失败是由于数据定义语言操作触发排序索引构建,禁用重做日志导致XtraBackup无法获取一致性备份。测试验证表明,优化表语句即使无数据也会触发该问题。根本原因在于排序索引构建过程跳过了重做日志记录,破坏了备份的一致性。
Kafka架构图优化与改进的全面详细步骤与实践指南
Kafka作为实时数据流处理的核心中间件,其底层架构虽已相当成熟,但在实际生产环境中,要充分发挥其性能潜力,仍需落实到具体的调优与架构改造上。核心目标可归纳为三点:如何承载更高的吞吐量、如何保障数据不丢失、以及故障发生时如何快速恢复。本文将从这几个关键方向出发,深入探讨如何真正榨干Kafka集群的性
- 热门数据榜
相关攻略
2026-07-25 22:22
2026-07-25 22:22
2026-07-25 22:22
2026-07-25 20:35
2026-07-25 20:35
2026-07-25 20:35
2026-07-25 20:35
2026-07-25 19:38
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程

