不用每次都重复写复杂操作,数据库也能“写脚本”
大家好呀!我是数据库小学妹👋
前几篇我们学会了视图,可以把复杂的查询存成虚拟表。但如果我们遇到这种情况如何解决:
如果我想执行一连串的操作(比如先更新A表,再插入B表,再删除C表),每次都要写好几条SQL。有没有办法把这一整套动作“打包”存起来,下次直接调用?
当然有!今天我就把自己学会的存储过程分享出来——它就像给数据库写“脚本”,把一堆SQL语句封装成一个整体,以后一句命令就能执行全部。
一、什么是存储过程?数据库里的“脚本文件”
存储过程是一段预先编译好并存储在数据库中的SQL代码。你可以给它起个名字,然后像调用函数一样执行它。
💡 类比:你在设计软件里录了一个“动作”宏,一键完成多步操作。存储过程就是数据库的“宏”。
为什么需要它?
- 复用性:写一次,调用无数次
- 减少网络传输:只需要发一条
CALL命令,而不是几十行SQL - 逻辑封装:把复杂的业务逻辑藏在存储过程里,应用层调用更简单
二、什么是存储过程?
📚基本语法
DELIMITER //
CREATE PROCEDURE 过程名()
BEGIN
-- 这里写SQL语句
SELECT 'Hello, Database!';
END //
DELIMITER ;
DELIMITER //是改变MySQL的语句结束符(因为过程体里可能有分号),执行完再改回;BEGIN...END之间放你要执行的SQL
调用存储过程
CALL 过程名();
🎯实战:无参存储过程示例
创建一个向日志表插入当前时间的存储过程:
DELIMITER //
CREATE PROCEDURE InsertLog()
BEGIN
INSERT INTO logs (message, created_at)
VALUES ('存储过程被执行了', NOW());
END //
DELIMITER ;
调用:
CALL InsertLog();
每次调用,logs 表里就会多一行记录。
三、存储过程的参数类型
参数可以让存储过程处理不同的数据。参数有三种类型:
示例1:IN参数——根据用户ID查询姓名
DELIMITER //
CREATE PROCEDURE GetUserName(IN user_id INT)
BEGIN
SELECT name FROM users WHERE id = user_id;
END //
DELIMITER ;
调用:
CALL GetUserName(1);
示例2:OUT参数——统计用户数量并返回
DELIMITER //
CREATE PROCEDURE GetUserCount(OUT total INT)
BEGIN
SELECT COUNT(*) INTO total FROM users;
END //
DELIMITER ;
调用:
CALL GetUserCount(@count);
SELECT @count; -- 查看输出参数的值
示例3:INOUT参数——对传入值做运算
DELIMITER //
CREATE PROCEDURE DoubleNumber(INOUT num INT)
BEGIN
SET num = num * 2;
END //
DELIMITER ;
调用:
SET @a = 5;
CALL DoubleNumber(@a);
SELECT @a; -- 结果是 10
四、存储过程的控制结构
在存储过程内部可以定义变量、使用条件判断和循环语句。
🎯定义变量
DECLARE 变量名 数据类型 [DEFAULT 默认值];
🎯IF-ELSE判断示例:根据分数返回等级
DELIMITER //
CREATE PROCEDURE GetGrade(IN score INT, OUT grade VARCHAR(10))
BEGIN
IF score >= 90 THEN
SET grade = '优秀';
ELSEIF score >= 60 THEN
SET grade = '及格';
ELSE
SET grade = '不及格';
END IF;
END //
DELIMITER ;
调用:
CALL GetGrade(85, @g);
SELECT @g; -- 及格
🎯CASE语句:多个条件时更清晰
比IF更适合多个固定值的匹配:
DELIMITER //
CREATE PROCEDURE GetWeekName(IN day_num INT, OUT week_name VARCHAR(10))
BEGIN
CASE day_num
WHEN 1 THEN SET week_name = '星期一';
WHEN 2 THEN SET week_name = '星期二';
WHEN 3 THEN SET week_name = '星期三';
WHEN 4 THEN SET week_name = '星期四';
WHEN 5 THEN SET week_name = '星期五';
WHEN 6 THEN SET week_name = '星期六';
WHEN 7 THEN SET week_name = '星期日';
ELSE SET week_name = '无效数字';
END CASE;
END //
DELIMITER ;
🎯WHILE循环:先判断后执行
批量插入数据(1到n):
DELIMITER //
CREATE PROCEDURE BatchInsert(IN n INT)
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= n DO
INSERT INTO test_table (value) VALUES (i);
SET i = i + 1;
END WHILE;
END //
DELIMITER ;
🎯LOOP循环:需配合 LEAVE 退出
DELIMITER //
CREATE PROCEDURE LoopExample(IN n INT)
BEGIN
DECLARE i INT DEFAULT 1;
loop_label: LOOP
IF i > n THEN
LEAVE loop_label; -- 退出循环
END IF;
INSERT INTO test_table (value) VALUES (i);
SET i = i + 1;
END LOOP;
END //
DELIMITER ;
💡 什么时候用哪种?
- 简单条件分支 →
IF- 多个固定值匹配 →
CASE- 已知循环次数 →
WHILE- 需要灵活控制(如无限循环+条件跳出) →
LOOP
注意:循环在数据量大时性能很差,实战中尽量避免。这里仅做语法演示。
五、查看和删除存储过程
查看所有存储过程
SHOW PROCEDURE STATUS WHERE Db = '你的数据库名';
查看存储过程的创建语句
SHOW CREATE PROCEDURE 过程名;
删除存储过程
DROP PROCEDURE IF EXISTS 过程名;
六、新手避坑指南(血泪总结)

七、存储过程与视图的区别?

简单总结:
- 只是查数据→ 视图
- 需要返回单个计算结果→ 函数
- 需要执行一系列操作(包括更新)→ 存储过程
八、今日学习心得
今天的内容总结成三句话:
- 存储过程就是数据库里的“函数”,封装复杂逻辑,一次编写多次调用
- 什么时候用:复杂业务逻辑、批量数据处理、提高性能
- 关键命令:
CREATE PROCEDURE→CALL→DROP PROCEDURE
👋 我是数据库小学妹一个用设计师思维学数据库的转行人
我们一起,把复杂的技术变得简单有趣!**💕---
本文为个人学习总结,所有命令均在MySQL 8.0环境下验证。存储过程是进阶技能,先掌握基础语法,再考虑实际应用。