存储过程

基本概念

存储过程和存储函数 事先经过编译并存储在数据库中的一段MySQL语句,类似于 Java 当中的方法, 可以对多组 SQL语句,进行封装操作。从 MySQL5.0 版本开始, 支持存储过程和存储函数。

  • 存储函数和存储过程的区别(了解)
  1. 1.存储函数:必须有返回值。
  2. 2.存储过程:可以没有返回值,也可以拥有返回值。
  • 优点和缺点(了解)
  1. 1.优点:
  2. A.存储过程可以封装 复杂的SQL语句,简化SQL的编写
  3. B.存储过程可以回传递增,并接受参数
  4. C.存储过程无法使用select指定来运行,与查看表数据或定义函数不同
  5. D.存储过程可以用在数据校验,强制实行商业逻辑等。
  6. 2.缺点:
  7. A.存储过程,往往制定在特定的数据库中,因为支持的编程语言不同,当切换其他厂商数据库时候,需要重写原有的存储过程。
  8. B.存储过程性能调校与撰写,受限于种种数据库系统。

步骤说明

  1. 1. 准备SQL表数据
  2. 2. 创建存储过程
  3. 3. 调用存储过程
  4. 4. 查看存储过程
  5. 5. 删除存储过程

准备数据

  1. -- 删除数据库 db7
  2. DROP DATABASE IF EXISTS db7;
  3. -- 创建db7数据库
  4. CREATE DATABASE IF NOT EXISTS db7 CHARACTER SET utf8;
  5. -- 使用数据库
  6. USE db7;
  7. -- 删除表数据
  8. DROP TABLE IF EXISTS student;
  9. -- 创建学生 student
  10. CREATE TABLE IF NOT EXISTS student(
  11. id INT, -- 学生id
  12. name VARCHAR(30), -- 学生姓名
  13. age INT, -- 学生年龄
  14. gender VARCHAR(20), -- 学生性别
  15. score INT -- 考试成绩
  16. );
  17. -- 添加数据
  18. INSERT INTO student VALUES (1,'张三',23,'男',95),(2,'李四',24,'男',98),(3,'王五',24,'女',100),(4,'赵六',26,'女',90);
  19. -- 查看结果
  20. SELECT * FROM student;
  21. -- 按照性别进行分组,查看每组学生的总成绩. 按照总成绩的升序排列
  22. SELECT gender,SUM(score) '总分' FROM student GROUP BY gender ORDER BY '总分' ASC;

创建存储过程

  • 语法
  1. -- 修改结束分隔符
  2. DELIMITER $
  3. -- 创建存储过程
  4. CREATE PROCEDURE 存储过程名称(参数列表)
  5. BEGIN
  6. SQL语句列表;
  7. END $
  8. -- 修改结束分隔符(⚠️警告:一定要打空格)
  9. DELIMITER ;
  • 举例
  1. -- 修改结束分隔符
  2. DELIMITER $
  3. -- 创建存储过程
  4. CREATE PROCEDURE stu_group ()
  5. BEGIN
  6. SELECT gender,SUM(score) FROM student GROUP BY gender;
  7. END $
  8. -- 修改结束分隔符
  9. DELIMITER ;

调用存储过程

  • 语法
  1. -- 调用存储过程
  2. CALL 存储过程名称(实际参数);
  • 举例
  1. -- 案例代码:调用存储过程
  2. call stu_group();

查看存储过程

  • 语法
  1. -- 查看存储过程(语法)
  2. SELECT * FROM mysql.proc WHERE db = '数据库名称';
  • 举例
  1. -- 案例代码: 查看存储过程
  2. SELECT * FROM mysql.proc WHERE db = 'db7';

删除存储过程

  • 语法
  1. -- 删除存储过程(语法)
  2. DROP PROCEDURE IF EXISTS 存储过程名称;
  • 举例
  1. -- 案例代码: 删除存储过程
  2. DROP PROCEDURE IF EXISTS stu_group;

存储过程 变量使用

  • 创建存储过程,并定义变量
  1. -- 修改结束符
  2. delimiter $
  3. -- 创建存储过程
  4. create procedure stu_getsum()
  5. -- 开始
  6. begin
  7. -- 定义变量total,默认值10(第一种)
  8. declare total int default 10;
  9. -- 修改变量total的值(第二种)
  10. set total=20;
  11. select 列名 into 变量名 from 表名 where条件;
  12. -- 查询student表的总分,赋值给变量total(第三种)
  13. select sum(score) into total from student;
  14. -- 查询total的结果
  15. select total;
  16. -- 结束
  17. end $
  18. -- 修改结束符(⚠️警告:一定要打空格)
  19. delimiter ;
  20. 举例:
  21. begin
  22. declare men,women int;
  23. select sum(score) into men from student where gender='男'
  24. select sumscore into women from student where='女'
  25. select men,women;
  26. end$
  • 调用存储过程
  1. call stu_getsum();

存储过程 if语句

  • 语法
  1. IF 判断条件 THEN 条件满足需要执行的语句;
  2. ELSEIF 判断条件 THEN 条件满足需要执行的语句;
  3. ELSE 其他情况下需要执行的语句;
  4. END IF;
  • 举例
  1. 需求:
  2. 1. 定义一个 int 类型的变量,用于存储班级的总成绩
  3. 2. 定义一个 varchar 类型的变量,用于存储分数的描述
  4. 3. 根据总成绩,进行判断
  5. 380分以上: 学习优秀
  6. 320-380分: 学习不错
  7. 320分以下: 学习一般
  1. -- 创建存储过程
  2. DELIMITER $
  3. CREATE PROCEDURE stu_if()
  4. BEGIN
  5. -- 定义变量,接收结果,查询总成绩赋值。
  6. DECLARE message VARCHAR(10);
  7. DECLARE total INT;
  8. SELECT SUM(score) INTO total FROM student;
  9. IF total > 380 THEN SET message = '学习优秀';
  10. ELSEIF total >= 320 AND total <= 380 THEN SET message = '学习不错';
  11. ELSE SET message = '学习一般';
  12. END IF;
  13. -- 查询总成绩和描述信息
  14. SELECT total,message;
  15. END $
  16. DELIMITER ;
  17. -- 03步:调用存储过程
  18. CALL stu_if();

存储过程 参数传递

  • 语法
  1. CREATE PROCEDURE 存储过程的名称([IN][OUT][INOUT] 参数名称 参数类型)
  2. BEGIN
  3. SQL语句列表;
  4. END $
  • 举例
  1. -- 01步: 删除存储过程
  2. DROP PROCEDURE IF EXISTS stu_param;
  3. -- 02步: 创建存储过程,设置为参数传递
  4. DELIMITER $
  5. CREATE PROCEDURE stu_param(IN total INT,INOUT message VARCHAR(20))
  6. BEGIN
  7. IF total>380 THEN SET message = '学习优秀';
  8. ELSEIF total>=320 AND total<=380 THEN SET message = '学习不错';
  9. ELSE SET message = '学习一般';
  10. END IF;
  11. END $
  12. DELIMITER ;
  13. -- 03步: 调用存储过程
  14. CALL stu_param(350,@message);
  15. -- 04步: 查询返回结果
  16. SELECT @message;

存储过程 循环

  • 语法
  1. 初始化语句;
  2. WHILE 条件判断语句 DO
  3. 循环体语句;
  4. 条件控制语句;
  5. END WHILE;
  • 举例
  1. -- 01步:删除存储过程
  2. DROP PROCEDURE IF EXISTS stu_loop;
  3. -- 02步:创建存储过程,计算 1-100 之间的偶数和
  4. DELIMITER $
  5. CREATE PROCEDURE stu_loop()
  6. BEGIN
  7. DECLARE result INT DEFAULT 0;
  8. DECLARE num INT DEFAULT 1;
  9. WHILE num <= 100 DO
  10. IF num % 2 = 0 THEN SET result = result + num;
  11. END IF;
  12. SET num = num + 1;
  13. END WHILE;
  14. SELECT result;
  15. END $
  16. DELIMITER ;
  17. -- 03步: 调用存储过程
  18. CALL stu_loop();

存储函数

存储函数和存储过程理解上是一样的,只是存储函数有返回值,必须写return语句。

无参数的存储函数

  • 创建存储函数格式
  1. DELIMITER $
  2. CREATE FUNCTION 函数名称(参数列表) RETURNS 返回值类型
  3. BEGIN
  4. SQL 语句列表;
  5. RETURN 结果;
  6. END $
  7. DELIMITER ;
  • 创建存储函数举例
  1. -- 查询学生表当中,成绩大于 95分的学生人数。
  2. -- 01步: 删除存储函数
  3. DROP FUNCTION IF EXISTS stu_hanshu;
  4. -- 02步: 创建存储函数
  5. DELIMITER $
  6. CREATE FUNCTION stu_hanshu() RETURNS INT
  7. BEGIN
  8. -- 定义变量,记录查询结果,返回
  9. DECLARE total INT;
  10. -- 获取到查询的结果
  11. SELECT COUNT(*) INTO total FROM student WHERE score>95;
  12. -- 返回结果
  13. RETURN total;
  14. END $
  15. DELIMITER ;
  16. -- 03步: 调用存储函数
  17. SELECT stu_hanshu();

有参数的存储函数

  1. -- 查询学生表当中,成绩大于 95分的学生人数。
  2. -- 01步: 删除存储函数
  3. DROP FUNCTION IF EXISTS stu_hanshu;
  4. -- 02步: 创建存储函数
  5. DELIMITER $
  6. CREATE FUNCTION stu_hanshu() RETURNS INT
  7. BEGIN
  8. -- 定义变量,记录查询结果,返回
  9. DECLARE total INT;
  10. -- 获取到查询的结果
  11. SELECT COUNT(*) INTO total FROM student WHERE score>95;
  12. -- 返回结果
  13. RETURN total;
  14. END $
  15. DELIMITER ;
  16. -- 03步: 调用存储函数
  17. SELECT stu_hanshu();

触发器

触发器就是在表数据发生变化的时候,自动触发的一些 SQL 操作。

这种特性可以协助应用系统在数据库端确保数据的完整性,日志记录,数据校验等操作

使用别名new和old来引用触发器中发生变化的内容记录。

触发器分类

触发器类型 OLD 触发器之前的效果 NEW 触发器之后的效果
INSERT
类型的触发器
无(因为插入前,没有之前的数据) NEW 表示将要或者已经新增的数据
UPDATE
类型的触发器
OLD 表示修改之前的数据 NEW 表示将要或者已经修改后的数据
DELETE
类型的触发器
OLD 表示将要或者已经修改的数据 无(因为删除后,状态无数据)

准备数据

  1. -- 删除数据库
  2. DROP DATABASE IF EXISTS db8;
  3. -- 创建数据库 db8
  4. CREATE DATABASE IF NOT EXISTS db8 CHARSET utf8;
  5. -- 使用数据库
  6. USE db8;
  7. -- 创建账户表
  8. CREATE TABLE IF NOT EXISTS account(
  9. id INT PRIMARY KEY AUTO_INCREMENT, -- 账户id
  10. NAME VARCHAR(20), -- 姓名
  11. money DOUBLE -- 余额
  12. );
  13. -- 添加数据
  14. INSERT INTO account VALUES (NULL,'张三',1000),(NULL,'李四',1000);
  15. -- 创建日志表 account_log
  16. CREATE TABLE IF NOT EXISTS account_log(
  17. id INT PRIMARY KEY AUTO_INCREMENT, -- 日志id
  18. operation VARCHAR(20), -- 操作的类型(insert update delete)
  19. operation_time DATETIME, -- 操作时间
  20. operation_id INT, -- 操作表的id
  21. operation_params VARCHAR(200) -- 操作参数
  22. );

INSERT 触发器

基础语法

  1. -- 删除触发器
  2. DROP TRIGGER IF EXISTS 触发器的名称;
  3. -- 02步,创建触发器
  4. DELIMITER $
  5. CREATE TRIGGER 触发器的名称
  6. AFTER INSERT ON 需要监测的表名称 FOR EACH ROW
  7. BEGIN
  8. INSERT INTO 记录结果的表名称 VALUES (值1,值2,值3,值4);
  9. END $
  10. DELIMITER ;

代码举例

  1. -- 创建 INSERT 类型的触发器
  2. -- 01步,删除触发器
  3. DROP TRIGGER IF EXISTS account_insert;
  4. -- 02步,创建触发器
  5. DELIMITER $
  6. CREATE TRIGGER account_insert
  7. AFTER INSERT ON account FOR EACH ROW
  8. BEGIN
  9. INSERT INTO account_log VALUES (
  10. NULL,
  11. 'INSERT',
  12. NOW(), -- 使用NOW函数,获取到当前的系统时间
  13. new.id,
  14. CONCAT('插入后{id=',new.id,'name=',new.name,'money=',new.money,'}')
  15. );
  16. END $
  17. DELIMITER ;
  18. -- 03步,向 account 表当中添加一条记录
  19. INSERT INTO account VALUES (NULL,'王五',2000);
  20. -- 04步, 查询 account 表记录
  21. SELECT * FROM account;
  22. -- 05步, 查询 account_log 表记录
  23. SELECT * FROM account_log;

UPDATE 触发器

基础语法

  1. -- 创建触发器, 创建更新的触发器
  2. DELIMITER $
  3. CREATE TRIGGER 触发器的名称
  4. AFTER UPDATE ON 需要监测的表名称 FOR EACH ROW
  5. BEGIN
  6. INSERT INTO 记录结果的表名称 VALUES (值1,值2,值3,值4);
  7. END $
  8. DELIMITER ;

代码实现

  1. -- 创建 UPDATE 类型的触发器
  2. -- 01步,删除触发器
  3. DROP TRIGGER IF EXISTS account_update;
  4. -- 02步,创建触发器
  5. DELIMITER $
  6. CREATE TRIGGER account_update
  7. AFTER UPDATE ON account FOR EACH ROW
  8. BEGIN
  9. INSERT INTO account_log VALUES (
  10. NULL,
  11. 'UPDATE',
  12. NOW(), -- 使用NOW函数,获取到当前的系统时间
  13. new.id,
  14. CONCAT('更新前{id=',old.id,'name=',old.name,'money=',old.money,'}',
  15. '更新后{id=',new.id,'name=',new.name,'money=',new.money,'}')
  16. );
  17. END $
  18. DELIMITER ;
  19. -- 03步,向 account 表当中更新一条记录
  20. UPDATE account SET money = money+10000 WHERE id = 1;
  21. -- 04步, 查询 account 表记录
  22. SELECT * FROM account;
  23. -- 05步, 查询 account_log 表记录
  24. SELECT * FROM account_log;

DELETE 触发器

基础语法

  1. -- 创建触发器, 创建删除的触发器
  2. DELIMITER $
  3. CREATE TRIGGER 触发器的名称
  4. AFTER DELETE ON 需要监测的表名称 FOR EACH ROW
  5. BEGIN
  6. INSERT INTO 记录结果的表名称 VALUES (值1,值2,值3,值4);
  7. END $
  8. DELIMITER ;

代码实现

  1. -- 创建 DELETE 类型的触发器
  2. -- 01步,删除触发器
  3. DROP TRIGGER IF EXISTS account_delete;
  4. -- 02步,创建触发器
  5. DELIMITER $
  6. CREATE TRIGGER account_delete
  7. AFTER DELETE ON account FOR EACH ROW
  8. BEGIN
  9. INSERT INTO account_log VALUES (
  10. NULL,
  11. 'DELETE',
  12. NOW(), -- 使用NOW函数,获取到当前的系统时间
  13. old.id,
  14. CONCAT('删除前{id=',old.id,'name=',old.name,'money=',old.money,'}')
  15. );
  16. END $
  17. DELIMITER ;
  18. -- 03步,向 account 表当中删除一条记录
  19. DELETE FROM account WHERE id = 2;
  20. -- 04步, 查询 account 表记录
  21. SELECT * FROM account;
  22. -- 05步, 查询 account_log 表记录
  23. SELECT * FROM account_log;

查看和删除触发器

  1. -- 1. 查看触发器
  2. SHOW TRIGGERS;
  3. -- 2. 删除触发器
  4. DROP TRIGGER 触发器的名称;

事务