存储过程
基本概念
存储过程和存储函数 事先经过编译并存储在数据库中的一段MySQL语句,类似于 Java 当中的方法, 可以对多组 SQL语句,进行封装操作。从 MySQL5.0 版本开始, 支持存储过程和存储函数。
- 存储函数和存储过程的区别(了解)
 
1.存储函数:必须有返回值。2.存储过程:可以没有返回值,也可以拥有返回值。
- 优点和缺点(了解)
 
1.优点:A.存储过程可以封装 复杂的SQL语句,简化SQL的编写B.存储过程可以回传递增,并接受参数C.存储过程无法使用select指定来运行,与查看表数据或定义函数不同D.存储过程可以用在数据校验,强制实行商业逻辑等。2.缺点:A.存储过程,往往制定在特定的数据库中,因为支持的编程语言不同,当切换其他厂商数据库时候,需要重写原有的存储过程。B.存储过程性能调校与撰写,受限于种种数据库系统。
步骤说明
1. 准备SQL表数据2. 创建存储过程3. 调用存储过程4. 查看存储过程5. 删除存储过程
准备数据
-- 删除数据库 db7DROP DATABASE IF EXISTS db7;-- 创建db7数据库CREATE DATABASE IF NOT EXISTS db7 CHARACTER SET utf8;-- 使用数据库USE db7;-- 删除表数据DROP TABLE IF EXISTS student;-- 创建学生 student 表CREATE TABLE IF NOT EXISTS student(id INT, -- 学生idname VARCHAR(30), -- 学生姓名age INT, -- 学生年龄gender VARCHAR(20), -- 学生性别score INT -- 考试成绩);-- 添加数据INSERT INTO student VALUES (1,'张三',23,'男',95),(2,'李四',24,'男',98),(3,'王五',24,'女',100),(4,'赵六',26,'女',90);-- 查看结果SELECT * FROM student;-- 按照性别进行分组,查看每组学生的总成绩. 按照总成绩的升序排列SELECT gender,SUM(score) '总分' FROM student GROUP BY gender ORDER BY '总分' ASC;
创建存储过程
- 语法
 
-- 修改结束分隔符DELIMITER $-- 创建存储过程CREATE PROCEDURE 存储过程名称(参数列表)BEGINSQL语句列表;END $-- 修改结束分隔符(⚠️警告:一定要打空格)DELIMITER ;
- 举例
 
-- 修改结束分隔符DELIMITER $-- 创建存储过程CREATE PROCEDURE stu_group ()BEGINSELECT gender,SUM(score) FROM student GROUP BY gender;END $-- 修改结束分隔符DELIMITER ;
调用存储过程
- 语法
 
-- 调用存储过程CALL 存储过程名称(实际参数);
- 举例
 
-- 案例代码:调用存储过程call stu_group();
查看存储过程
- 语法
 
-- 查看存储过程(语法)SELECT * FROM mysql.proc WHERE db = '数据库名称';
- 举例
 
-- 案例代码: 查看存储过程SELECT * FROM mysql.proc WHERE db = 'db7';
删除存储过程
- 语法
 
-- 删除存储过程(语法)DROP PROCEDURE IF EXISTS 存储过程名称;
- 举例
 
-- 案例代码: 删除存储过程DROP PROCEDURE IF EXISTS stu_group;
存储过程 变量使用
- 创建存储过程,并定义变量
 
-- 修改结束符delimiter $-- 创建存储过程create procedure stu_getsum()-- 开始begin-- 定义变量total,默认值10(第一种)declare total int default 10;-- 修改变量total的值(第二种)set total=20;select 列名 into 变量名 from 表名 where条件;-- 查询student表的总分,赋值给变量total(第三种)select sum(score) into total from student;-- 查询total的结果select total;-- 结束end $-- 修改结束符(⚠️警告:一定要打空格)delimiter ;举例:begindeclare men,women int;select sum(score) into men from student where gender='男';select sum(score) into women from student where='女';select men,women;end$
- 调用存储过程
 
call stu_getsum();
存储过程 if语句
- 语法
 
IF 判断条件 THEN 条件满足需要执行的语句;ELSEIF 判断条件 THEN 条件满足需要执行的语句;ELSE 其他情况下需要执行的语句;END IF;
- 举例
 
需求:1. 定义一个 int 类型的变量,用于存储班级的总成绩2. 定义一个 varchar 类型的变量,用于存储分数的描述3. 根据总成绩,进行判断380分以上: 学习优秀320-380分: 学习不错320分以下: 学习一般
-- 创建存储过程DELIMITER $CREATE PROCEDURE stu_if()BEGIN-- 定义变量,接收结果,查询总成绩赋值。DECLARE message VARCHAR(10);DECLARE total INT;SELECT SUM(score) INTO total FROM student;IF total > 380 THEN SET message = '学习优秀';ELSEIF total >= 320 AND total <= 380 THEN SET message = '学习不错';ELSE SET message = '学习一般';END IF;-- 查询总成绩和描述信息SELECT total,message;END $DELIMITER ;-- 第03步:调用存储过程CALL stu_if();
存储过程 参数传递
- 语法
 
CREATE PROCEDURE 存储过程的名称([IN][OUT][INOUT] 参数名称 参数类型)BEGINSQL语句列表;END $
- 举例
 
-- 第01步: 删除存储过程DROP PROCEDURE IF EXISTS stu_param;-- 第02步: 创建存储过程,设置为参数传递DELIMITER $CREATE PROCEDURE stu_param(IN total INT,INOUT message VARCHAR(20))BEGINIF total>380 THEN SET message = '学习优秀';ELSEIF total>=320 AND total<=380 THEN SET message = '学习不错';ELSE SET message = '学习一般';END IF;END $DELIMITER ;-- 第03步: 调用存储过程CALL stu_param(350,@message);-- 第04步: 查询返回结果SELECT @message;
存储过程 循环
- 语法
 
初始化语句;WHILE 条件判断语句 DO循环体语句;条件控制语句;END WHILE;
- 举例
 
-- 第01步:删除存储过程DROP PROCEDURE IF EXISTS stu_loop;-- 第02步:创建存储过程,计算 1-100 之间的偶数和DELIMITER $CREATE PROCEDURE stu_loop()BEGINDECLARE result INT DEFAULT 0;DECLARE num INT DEFAULT 1;WHILE num <= 100 DOIF num % 2 = 0 THEN SET result = result + num;END IF;SET num = num + 1;END WHILE;SELECT result;END $DELIMITER ;-- 第03步: 调用存储过程CALL stu_loop();
存储函数
存储函数和存储过程理解上是一样的,只是存储函数有返回值,必须写return语句。
无参数的存储函数
- 创建存储函数格式
 
DELIMITER $CREATE FUNCTION 函数名称(参数列表) RETURNS 返回值类型BEGINSQL 语句列表;RETURN 结果;END $DELIMITER ;
- 创建存储函数举例
 
-- 查询学生表当中,成绩大于 95分的学生人数。-- 第01步: 删除存储函数DROP FUNCTION IF EXISTS stu_hanshu;-- 第02步: 创建存储函数DELIMITER $CREATE FUNCTION stu_hanshu() RETURNS INTBEGIN-- 定义变量,记录查询结果,返回DECLARE total INT;-- 获取到查询的结果SELECT COUNT(*) INTO total FROM student WHERE score>95;-- 返回结果RETURN total;END $DELIMITER ;-- 第03步: 调用存储函数SELECT stu_hanshu();
有参数的存储函数
-- 查询学生表当中,成绩大于 95分的学生人数。-- 第01步: 删除存储函数DROP FUNCTION IF EXISTS stu_hanshu;-- 第02步: 创建存储函数DELIMITER $CREATE FUNCTION stu_hanshu() RETURNS INTBEGIN-- 定义变量,记录查询结果,返回DECLARE total INT;-- 获取到查询的结果SELECT COUNT(*) INTO total FROM student WHERE score>95;-- 返回结果RETURN total;END $DELIMITER ;-- 第03步: 调用存储函数SELECT stu_hanshu();
触发器
触发器就是在表数据发生变化的时候,自动触发的一些 SQL 操作。
这种特性可以协助应用系统在数据库端确保数据的完整性,日志记录,数据校验等操作
使用别名new和old来引用触发器中发生变化的内容记录。
触发器分类
| 触发器类型 | OLD 触发器之前的效果 | NEW 触发器之后的效果 | 
|---|---|---|
INSERT类型的触发器  | 
无(因为插入前,没有之前的数据) | NEW 表示将要或者已经新增的数据 | 
UPDATE类型的触发器  | 
OLD 表示修改之前的数据 | NEW 表示将要或者已经修改后的数据 | 
DELETE类型的触发器  | 
OLD 表示将要或者已经修改的数据 | 无(因为删除后,状态无数据) | 
准备数据
-- 删除数据库DROP DATABASE IF EXISTS db8;-- 创建数据库 db8CREATE DATABASE IF NOT EXISTS db8 CHARSET utf8;-- 使用数据库USE db8;-- 创建账户表CREATE TABLE IF NOT EXISTS account(id INT PRIMARY KEY AUTO_INCREMENT, -- 账户idNAME VARCHAR(20), -- 姓名money DOUBLE -- 余额);-- 添加数据INSERT INTO account VALUES (NULL,'张三',1000),(NULL,'李四',1000);-- 创建日志表 account_logCREATE TABLE IF NOT EXISTS account_log(id INT PRIMARY KEY AUTO_INCREMENT, -- 日志idoperation VARCHAR(20), -- 操作的类型(insert update delete)operation_time DATETIME, -- 操作时间operation_id INT, -- 操作表的idoperation_params VARCHAR(200) -- 操作参数);
INSERT 触发器
基础语法
-- 删除触发器DROP TRIGGER IF EXISTS 触发器的名称;-- 第02步,创建触发器DELIMITER $CREATE TRIGGER 触发器的名称AFTER INSERT ON 需要监测的表名称 FOR EACH ROWBEGININSERT INTO 记录结果的表名称 VALUES (值1,值2,值3,值4);END $DELIMITER ;
代码举例
-- 创建 INSERT 类型的触发器-- 第01步,删除触发器DROP TRIGGER IF EXISTS account_insert;-- 第02步,创建触发器DELIMITER $CREATE TRIGGER account_insertAFTER INSERT ON account FOR EACH ROWBEGININSERT INTO account_log VALUES (NULL,'INSERT',NOW(), -- 使用NOW函数,获取到当前的系统时间new.id,CONCAT('插入后{id=',new.id,'name=',new.name,'money=',new.money,'}'));END $DELIMITER ;-- 第03步,向 account 表当中添加一条记录INSERT INTO account VALUES (NULL,'王五',2000);-- 第04步, 查询 account 表记录SELECT * FROM account;-- 第05步, 查询 account_log 表记录SELECT * FROM account_log;
UPDATE 触发器
基础语法
-- 创建触发器, 创建更新的触发器DELIMITER $CREATE TRIGGER 触发器的名称AFTER UPDATE ON 需要监测的表名称 FOR EACH ROWBEGININSERT INTO 记录结果的表名称 VALUES (值1,值2,值3,值4);END $DELIMITER ;
代码实现
-- 创建 UPDATE 类型的触发器-- 第01步,删除触发器DROP TRIGGER IF EXISTS account_update;-- 第02步,创建触发器DELIMITER $CREATE TRIGGER account_updateAFTER UPDATE ON account FOR EACH ROWBEGININSERT INTO account_log VALUES (NULL,'UPDATE',NOW(), -- 使用NOW函数,获取到当前的系统时间new.id,CONCAT('更新前{id=',old.id,'name=',old.name,'money=',old.money,'}','更新后{id=',new.id,'name=',new.name,'money=',new.money,'}'));END $DELIMITER ;-- 第03步,向 account 表当中更新一条记录UPDATE account SET money = money+10000 WHERE id = 1;-- 第04步, 查询 account 表记录SELECT * FROM account;-- 第05步, 查询 account_log 表记录SELECT * FROM account_log;
DELETE 触发器
基础语法
-- 创建触发器, 创建删除的触发器DELIMITER $CREATE TRIGGER 触发器的名称AFTER DELETE ON 需要监测的表名称 FOR EACH ROWBEGININSERT INTO 记录结果的表名称 VALUES (值1,值2,值3,值4);END $DELIMITER ;
代码实现
-- 创建 DELETE 类型的触发器-- 第01步,删除触发器DROP TRIGGER IF EXISTS account_delete;-- 第02步,创建触发器DELIMITER $CREATE TRIGGER account_deleteAFTER DELETE ON account FOR EACH ROWBEGININSERT INTO account_log VALUES (NULL,'DELETE',NOW(), -- 使用NOW函数,获取到当前的系统时间old.id,CONCAT('删除前{id=',old.id,'name=',old.name,'money=',old.money,'}'));END $DELIMITER ;-- 第03步,向 account 表当中删除一条记录DELETE FROM account WHERE id = 2;-- 第04步, 查询 account 表记录SELECT * FROM account;-- 第05步, 查询 account_log 表记录SELECT * FROM account_log;
查看和删除触发器
-- 1. 查看触发器SHOW TRIGGERS;-- 2. 删除触发器DROP TRIGGER 触发器的名称;
