-- 使用OUT参数返回结果 DELIMITER // CREATEPROCEDURE dorepeat_improved(IN n INT, OUTresultINT) BEGIN DECLARE i INTDEFAULT0; DECLARE sum_val INTDEFAULT0; REPEAT SET sum_val = sum_val + i; SET i = i +1; UNTIL i > n END REPEAT; SETresult= sum_val; END// DELIMITER ;
-- 创建学生信息管理存储过程 DELIMITER // CREATEPROCEDURE manageStudent( IN action VARCHAR(10), IN student_id INT, IN student_name VARCHAR(50), OUT result_message VARCHAR(100) ) BEGIN DECLARE student_count INT; IF action ='INSERT'THEN INSERTINTO students(name) VALUES(student_name); SET result_message = CONCAT('学生 ', student_name, ' 添加成功'); ELSEIF action ='UPDATE'THEN SELECTCOUNT(*) INTO student_count FROM students WHERE id = student_id; IF student_count >0THEN UPDATE students SET name = student_name WHERE id = student_id; SET result_message ='学生信息更新成功'; ELSE SET result_message ='学生不存在'; END IF; ELSEIF action ='DELETE'THEN SELECTCOUNT(*) INTO student_count FROM students WHERE id = student_id; IF student_count >0THEN DELETEFROM students WHERE id = student_id; SET result_message ='学生删除成功'; ELSE SET result_message ='学生不存在'; END IF; ELSE SET result_message ='无效的操作'; END IF; END// DELIMITER ;
CREATEPROCEDURE local_variable_example() BEGIN DECLARE local_var INTDEFAULT0; DECLARE var_name VARCHAR(50); SET local_var =100; SET var_name ='Test'; SELECT local_var, var_name; END;
特点:
存储过程内有效
使用DECLARE声明
必须指定数据类型
可以有默认值
8.2 控制结构
IF语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
CREATEPROCEDURE if_example(IN score INT) BEGIN DECLARE grade VARCHAR(10); IF score >=90THEN SET grade ='A'; ELSEIF score >=80THEN SET grade ='B'; ELSEIF score >=70THEN SET grade ='C'; ELSE SET grade ='F'; END IF; SELECT grade; END;
CREATEPROCEDURE while_example(IN n INT) BEGIN DECLARE i INTDEFAULT1; DECLARE sum INTDEFAULT0; WHILE i <= n DO SET sum = sum + i; SET i = i +1; END WHILE; SELECT sum; END;
REPEAT循环:
1 2 3 4 5 6 7 8 9 10 11 12
CREATEPROCEDURE repeat_example(IN n INT) BEGIN DECLARE i INTDEFAULT1; DECLARE sum INTDEFAULT0; REPEAT SET sum = sum + i; SET i = i +1; UNTIL i > n END REPEAT; SELECT sum; END;
LOOP循环:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
CREATEPROCEDURE loop_example(IN n INT) BEGIN DECLARE i INTDEFAULT1; DECLARE sum INTDEFAULT0; my_loop: LOOP SET sum = sum + i; SET i = i +1; IF i > n THEN LEAVE my_loop; END IF; END LOOP; SELECT sum; END;
8.3 错误处理
使用SIGNAL抛出错误
1 2 3 4 5 6 7 8 9
CREATEPROCEDURE error_example(INvalueINT) BEGIN IF value<0THEN SIGNAL SQLSTATE'45000' SET MESSAGE_TEXT ='值不能为负数'; END IF; SELECTvalue; END;
使用HANDLER处理错误
1 2 3 4 5 6 7 8 9 10
CREATEPROCEDURE handler_example() BEGIN DECLARE CONTINUE HANDLER FORSQLEXCEPTION BEGIN SELECT'发生错误'AS error_message; END; -- 可能出错的SQL语句 INSERTINTO table_name VALUES(...); END;
CREATEPROCEDURE cursor_example() BEGIN DECLARE done INTDEFAULTFALSE; DECLARE student_name VARCHAR(50); DECLARE cur CURSORFOR SELECT name FROM students; DECLARE CONTINUE HANDLER FORNOT FOUND SET done =TRUE; OPEN cur; read_loop: LOOP FETCH cur INTO student_name; IF done THEN LEAVE read_loop; END IF; -- 处理数据 SELECT student_name; END LOOP; CLOSE cur; END;
9. 存储过程与自定义函数的区别
9.1 功能复杂度
特性
存储过程
自定义函数
功能复杂度
可以实现复杂的过程逻辑
针对性较强,功能相对简单
业务逻辑
适合复杂业务逻辑
适合简单计算和转换
9.2 返回值
特性
存储过程
自定义函数
返回值数量
可以有多个返回值(通过OUT参数)
只有一个返回值
返回值方式
OUT参数、结果集
RETURN语句
返回值类型
可以是结果集
必须是标量值
示例对比:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
-- 存储过程:多个OUT参数 CREATEPROCEDURE getInfo( OUT name VARCHAR(50), OUT age INT, OUT email VARCHAR(100) ) BEGIN SELECT'John', 25, 'john@example.com'INTO name, age, email; END;
-- 函数:单个返回值 CREATEFUNCTION getAge(birth_date DATE) RETURNSINT BEGIN RETURNYEAR(CURDATE()) -YEAR(birth_date); END;
9.3 调用方式
特性
存储过程
自定义函数
调用方式
CALL procedure_name()
SELECT function_name()
使用场景
独立执行
作为SQL语句的一部分
结果处理
可以返回结果集
返回标量值
示例对比:
1 2 3 4 5 6
-- 存储过程:独立调用 CALL getStudentInfo(1);
-- 函数:作为SQL的一部分 SELECT name, getAge(birth_date) AS age FROM students; SELECT*FROM students WHERE getAge(birth_date) >18;
CREATEPROCEDURE robust_example(INvalueINT) BEGIN DECLARE EXIT HANDLER FORSQLEXCEPTION BEGIN ROLLBACK; SELECT'操作失败'AS error; END; START TRANSACTION; -- 业务逻辑 COMMIT; END;
10.4 性能优化
1. 避免在循环中执行查询
1 2 3 4 5 6 7 8
-- 不推荐 WHILE i < n DO SELECT*FROMtableWHERE id = i; -- 每次循环都查询 SET i = i +1; END WHILE;
-- 推荐:批量查询 SELECT*FROMtableWHERE id IN (1,2,3,...);
2. 使用临时表
1 2 3 4 5 6 7 8 9 10
CREATEPROCEDURE temp_table_example() BEGIN CREATE TEMPORARY TABLE temp_results AS SELECT*FROM large_table WHEREcondition; -- 使用临时表处理 SELECT*FROM temp_results; DROP TEMPORARY TABLE temp_results; END;
10.5 文档和注释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
CREATEPROCEDURE documented_example( IN student_id INT, OUT student_name VARCHAR(50) ) COMMENT '根据学生ID获取学生姓名' BEGIN -- 功能:根据学生ID查询学生姓名 -- 参数:student_id - 学生ID -- 返回:student_name - 学生姓名 -- 作者:架构师 -- 日期:2019-03-08 SELECT name INTO student_name FROM students WHERE id = student_id; END;
11. 存储过程调试技巧
11.1 使用SELECT输出调试信息
1 2 3 4 5 6
CREATEPROCEDURE debug_example(INvalueINT) BEGIN SELECT CONCAT('Input value: ', value) AS debug; SET@debug_var =value*2; SELECT CONCAT('Calculated: ', @debug_var) AS debug; END;