MySQL存储过程游标循环详解:批量汇总成绩数据实战

何川
何川
发布时间:2026-10-13| 4人浏览过
原创

本文详细解析MySQL中存储过程的游标循环机制,并通过学生成绩数据汇总的完整案例,展示如何结合DECLARE变量、CONTINUE HANDLER异常处理以及REPEAT循环语句实现批量数据处理。内容涵盖从表结构搭建、SQL脚本编写到存储过程调用的全过程,并针对存储过程在业务维护中的优缺点提出专业建议。

核心目标与准备条件

在关系型数据库操作中,当面临需要将一个集合的数据逐个提取并进行复杂计算或状态变更时,存储过程配合游标(Cursor)是实现这种逐行处理逻辑的有效手段。本案例旨在解决以下问题:

  • 背景:存在学生基础信息表和学生成绩明细表,需要定期生成每个学生每年度的成绩汇总表。
  • 方案对比:虽然可以在应用层(如Java/Python代码)获取数据后循环处理,但在数据库端通过存储过程直接在服务器端完成聚合运算,能减少网络I/O并简化客户端复杂度。
  • 技术栈:MySQL 5.7+ / 8.0+

第一步:构建实验数据环境

为了清晰演示存储过程的逻辑,我们需要先建立三张关联表:t_student(学生基本信息)、t_achievement(原始成绩记录)、t_achievement_report(最终生成的汇总表)。

1.1 创建学生表与成绩表

-- 学生信息表
DROP TABLE IF EXISTS t_student;
CREATE TABLE `t_student` (
  -- 省略字段定义... 见下方完整脚本
) CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- 学生成绩表
DROP TABLE IF EXISTS t_achievement;
CREATE TABLE `t_achievement` (
  `id` BIGINT(12) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `year` INT(4) NOT NULL COMMENT '学年',
  `subject` CHAR(2) NOT NULL COMMENT '科目',
  `score` INT(3) NOT NULL COMMENT '得分',
  `student_id` BIGINT(12) NOT NULL COMMENT '所属学生id',
  PRIMARY KEY (`id`) 
) CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

1.2 创建汇总表

-- 成绩汇总表
DROP TABLE IF EXISTS t_achievement_report;
CREATE TABLE `t_achievement_report` (
  `id` BIGINT(12) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `student_id` BIGINT(12) NOT NULL COMMENT '学生id',
  `year` INT(4) NOT NULL COMMENT '学年',
  `total_score` INT(4) NOT NULL COMMENT '总分',
  `avg_score` DECIMAL(4,2) NOT NULL COMMENT '平均分',
  PRIMARY KEY (`id`) 
) CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

1.3 插入测试数据

插入少量代表性数据,模拟真实的业务录入情况:

INSERT INTO t_student(id, CODE, NAME, age, gender) VALUES
(1, '2022010101', '小张', 18, 'M'),
(2, '2022010102', '小李', 18, 'F'),
(3, '2022010103', '小明', 18, 'M');

INSERT INTO t_achievement(YEAR, SUBJECT, score, student_id) VALUES
(2022, '01', 80, 1), (2022, '02', 85, 1), (2022, '03', 90, 1),
(2022, '01', 60, 2), (2022, '02', 90, 2), (2022, '03', 98, 2),
(2022, '01', 75, 3), (2022, '02', 100, 3), (2022, '03', 85, 3);

第二步:编写带游标循环的存储过程

这是核心步骤。存储过程需要通过游标逐行读取 t_student 中的学生ID,随后针对该ID执行成绩聚合,并防止重复计算。以下是完整的存储过程代码及其逻辑拆解:

DELIMITER $$
CREATE PROCEDURE statistics_achievement()
BEGIN
	-- 1. 定义结束标志变量
	DECLARE done BOOLEAN DEFAULT FALSE;
	-- 2. 定义用于接收游标数据的变量
	DECLARE studentid BIGINT(12);
	-- 3. 声明游标,指向要遍历的学生ID集合
	DECLARE cursor_student CURSOR FOR SELECT id FROM t_student;
	-- 4. 定义句柄(Handler),当SQLSTATE为'02000'(即没有更多数据可取)时,将done置为TRUE
	DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=TRUE;
	
	-- 打开游标
	OPEN cursor_student;
	
	-- 5. REPEAT 循环结构:至少执行一次,直到条件满足
	REPEAT 
		-- 从游标中取出当前行的id赋值给studentid变量
		FETCH cursor_student INTO studentid;
		
		-- 如果done为true说明已读完,此时跳出循环前不执行INSERT
		IF NOT done THEN
			-- 计算该学生在该学年的总分和平均分,并检查是否已存在该年份的记录以防重复入库
			INSERT INTO t_achievement_report(student_id, -- 对应字段: YEAR, total_score, avg_score)
			SELECT studentid, `YEAR`, SUM(score), ROUND(SUM(score) / 3, 2) 
			FROM t_achievement t1 
			WHERE student_id = studentid 
			AND NOT EXISTS(
				SELECT 1 FROM t_achievement_report t2 
				WHERE student_id = studentid AND t1.year = t2.year
			) 
			GROUP BY `YEAR`;
		END IF;
	UNTIL done END REPEAT;
	
	-- 关闭游标释放资源
	CLOSE cursor_student;
END$$
DELIMITER ;

关键语法解析

  • DELIMITER $$:临时修改语句分隔符,因为存储过程内部包含分号 ;,避免MySQL误判语句结束。
  • DECLARE CONTINUE HANDLER...:这是控制循环结束的关键。当游标试图 FETCH 下一行但已不存在数据时,MySQL返回 SQLSTATE '02000',触发 Handler 将 done 设为 TRUE。
  • REPEAT ... UNTIL:类似于其他编程语言的 Do-While 循环。

第三步:执行与验证

3.1 调用存储过程

CALL statistics_achievement();

3.2 查看执行结果

执行上述命令后,数据库将开始运行循环。你可以查询汇总表来验证数据是否正确入库:

SELECT * FROM t_achievement_report;

正常情况下,表中应该出现三条记录,分别对应三位学生2022年度的总分和平均分。如果出现报错,通常是因表结构不一致或权限不足导致。

总结与注意事项

MySQL存储过程功能强大,尤其适合处理复杂的数据清洗、历史数据迁移(割接)或报表聚合等批量任务。在处理大量静态数据更新时,它能显著减少应用服务器的负载。

然而,对于高并发的日常业务逻辑(如订单创建、实时状态流转),强烈不建议使用存储过程。原因如下:

  • 维护成本高:业务逻辑分散在数据库代码中,缺乏版本控制工具的支持,排查问题困难。
  • 扩展性差:难以平滑迁移至微服务架构或分布式数据库集群。
  • 性能瓶颈:MySQL单线程执行特性可能导致在极高并发下成为数据库的阻塞点。

总之,掌握游标和循环是理解MySQL内部逻辑的重要一步,但在实际开发选型中,请根据业务的具体场景权衡利弊。以上就是MySQL存储过程循环使用的详细内容,更多关于MySQL进阶优化的资料请关注本站其它相关文章!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。