【SQL】深入理解MySQL存储过程:MySQL流程控制语句详解
一、前置知识
- 流程控制语句只能在
BEGIN ... END
块中使用。 - 常用于实现条件判断、循环处理等逻辑。
- 需要配合变量使用(如
DECLARE
声明变量,SET
赋值)。
DELIMITER $$CREATE PROCEDURE 示例流程控制()
BEGIN-- 在这里使用 IF、CASE、WHILE 等语句
END$$DELIMITER ;
二、1. IF
语句 —— 条件判断
✅ 语法结构:
IF 条件 THEN语句1;
[ELSEIF 条件2 THEN语句2;]
[ELSE其他语句;]
END IF;
🔍 示例:根据成绩判断等级
DELIMITER $$CREATE PROCEDURE GetGrade(IN score INT)
BEGINIF score >= 90 THENSELECT '优秀' AS level;ELSEIF score >= 80 THENSELECT '良好' AS level;ELSEIF score >= 60 THENSELECT '及格' AS level;ELSESELECT '不及格' AS level;END IF;
END$$DELIMITER ;-- 调用
CALL GetGrade(85); -- 输出:良好
二、2. CASE
语句 —— 多分支选择
有两种形式:简单 CASE 和 搜索型 CASE
✅ 形式一:简单 CASE(类似 switch)
CASE 变量WHEN 值1 THEN 语句1;WHEN 值2 THEN 语句2;ELSE 其他语句;
END CASE;
示例:根据数字输出星期名称
DELIMITER $$CREATE PROCEDURE GetWeekday(IN day INT)
BEGINCASE dayWHEN 1 THEN SELECT '星期一' AS weekday;WHEN 2 THEN SELECT '星期二' AS weekday;WHEN 3 THEN SELECT '星期三' AS weekday;ELSE SELECT '未知' AS weekday;END CASE;
END$$DELIMITER ;CALL GetWeekday(2); -- 输出:星期二
✅ 形式二:搜索型 CASE(基于条件判断)
CASEWHEN 条件1 THEN 语句1;WHEN 条件2 THEN 语句2;ELSE 其他语句;
END CASE;
示例:判断年龄阶段
DELIMITER $$CREATE PROCEDURE CheckAgeGroup(IN age INT)
BEGINCASEWHEN age < 13 THEN SELECT '儿童' AS group_name;WHEN age BETWEEN 13 AND 17 THEN SELECT '青少年';WHEN age BETWEEN 18 AND 65 THEN SELECT '成年人';ELSE SELECT '老年人';END CASE;
END$$DELIMITER ;CALL CheckAgeGroup(25); -- 输出:成年人
💡 提示:
CASE
更适合多分支选择,代码更清晰。
三、循环结构概述
MySQL 支持三种循环结构:
循环类型 | 特点 |
---|---|
WHILE | 先判断条件,再执行(可能一次都不执行) |
REPEAT | 先执行一次,再判断是否继续(至少执行一次) |
LOOP | 无条件循环,需手动 LEAVE 退出 |
所有循环都可通过 ITERATE
(继续)和 LEAVE
(跳出)控制流程。
三、1. WHILE
循环 —— 当型循环
✅ 语法:
[label:] WHILE 条件 DO循环体语句;
END WHILE [label];
🔍 示例:计算 1 到 n 的和
DELIMITER $$CREATE PROCEDURE SumToN(IN n INT, OUT result INT)
BEGINDECLARE i INT DEFAULT 1;SET result = 0;WHILE i <= n DOSET result = result + i;SET i = i + 1;END WHILE;
END$$DELIMITER ;-- 调用
CALL SumToN(100, @sum);
SELECT @sum; -- 输出:5050
三、2. REPEAT
循环 —— 直到型循环(类似 do-while)
✅ 语法:
[label:] REPEAT循环体语句;
UNTIL 条件
END REPEAT [label];
⚠️ 注意:
UNTIL
后的条件为 真时退出循环
🔍 示例:打印数字直到大于 5
DELIMITER $$CREATE PROCEDURE PrintUntil5()
BEGINDECLARE i INT DEFAULT 1;REPEATSELECT i; -- 每次输出当前 iSET i = i + 1;UNTIL i > 5END REPEAT;
END$$DELIMITER ;CALL PrintUntil5();
-- 输出 1, 2, 3, 4, 5 (每次 SELECT 一行)
三、3. LOOP
循环 —— 手动控制的无限循环
✅ 语法:
[label:] LOOP循环体语句;-- 必须有 LEAVE 或 ITERATE
END LOOP [label];
控制关键字:
LEAVE label
:相当于break
,跳出循环ITERATE label
:相当于continue
,跳回循环开头
🔍 示例:使用 LOOP 计算 1~100 的和
DELIMITER $$CREATE PROCEDURE SumWithLoop(IN n INT, OUT result INT)
BEGINDECLARE i INT DEFAULT 1;SET result = 0;sum_loop: LOOPIF i > n THENLEAVE sum_loop; -- 相当于 breakEND IF;SET result = result + i;SET i = i + 1;END LOOP sum_loop;
END$$DELIMITER ;CALL SumWithLoop(100, @res);
SELECT @res; -- 输出:5050
四、高级技巧:标签(Label)与流程跳转
使用标签提升可读性与控制力
outer_loop: LOOPinner_loop: WHILE i < 10 DOIF condition THENLEAVE outer_loop; -- 直接跳出外层循环END IF;END WHILE inner_loop;
END LOOP outer_loop;
✅ 标签命名建议:
loop_name
、exit_loop
、continue_loop
等,增强可读性。
五、综合实战:生成斐波那契数列前 N 项
DELIMITER $$CREATE PROCEDURE FibSequence(IN n INT)
BEGINDECLARE a INT DEFAULT 0;DECLARE b INT DEFAULT 1;DECLARE i INT DEFAULT 1;DECLARE temp INT;IF n <= 0 THENSELECT '请输入正整数' AS msg;ELSEWHILE i <= n DOSELECT a AS fibonacci; -- 输出当前项SET temp = a + b;SET a = b;SET b = temp;SET i = i + 1;END WHILE;END IF;
END$$DELIMITER ;CALL FibSequence(8);
-- 输出:0, 1, 1, 2, 3, 5, 8, 13
六、常见错误与注意事项
错误 | 解决方法 |
---|---|
忘记 DELIMITER 导致语法错误 | 使用 DELIMITER $$ 避免 ; 提前结束 |
变量未声明 | 使用 DECLARE 在 BEGIN 后第一行声明 |
循环未设置退出条件 | 导致死循环(MySQL 会超时中断) |
CASE 缺少 END CASE | 语法错误,必须配对 |
在函数中使用 SELECT 直接输出结果集 | ❌ 函数不能返回结果集,只能返回单值 |
七、总结对比表
语句 | 用途 | 是否必须结束条件 | 类似语言中的 |
---|---|---|---|
IF | 条件分支 | 否 | if-else |
CASE | 多分支选择 | 否 | switch / if-elif |
WHILE | 先判断后执行 | 是 | while |
REPEAT | 先执行后判断 | 是 | do-while |
LOOP | 自定义循环 | 手动 LEAVE | for(;😉 / goto |