MySQL基础篇-11-存储过程和存储函数
存储过程概述
概念
存储过程就是一组经过预先编译的 SQL 语句的封装。 存储过程预先存储在 MySQL 服务器上,需要执行时客户端只需要向服务器端发出调用存储过程的命令,服务器端就可以把预先存储好的这一系列 SQL 语句全部执行。
优点
- 简化操作,提高 SQL 语句的重用性
- 减少操作过程中的失误,提高效率
- 减少网络传输量(客户端不需要把所有的 SQL 语句通过网络发给服务器)
- 减少了 SQL 语句暴露的风险,也提高了数据查询的安全性
与函数相比
一旦存储过程被创建出来,使用它就像使用函数一样简单,我们直接通过调用存储过程名即可。相较于函数,存储过程是没有返回值的。
分类
分类 | 说明 |
---|---|
没有参数 | 无参数无返回 |
仅仅带 IN 类型 | 有参数无返回 |
仅仅带 OUT 类型 | 无参数有返 回 |
既带 IN 又带 OUT | 有参数有返回 |
带 INOUT | 有参数有返回 |
创建存储过程
语法
1 | CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名 参数类型,...) |
符号说明
- IN :当前参数为输入参数。 存储过程只是读取这个参数的值。如果没有定义参数种类, 默认就是 IN ,表示输入参数
- OUT :当前参数为输出参数。 执行完成之后,调用这个存储过程的客户端或者应用程序就可以读取这个参数返回的值
- INOUT :当前参数既可以为输入参数,也可以为输出参数
characteristics
表示创建存储过程时指定的对存储过程的约束条件
1 | LANGUAGE SQL |
LANGUAGE SQL
:说明存储过程执行体是由 SQL 语句组成的,即当前系统支持的语言为 SQL[NOT] DETERMINISTIC
:指明存储过程执行的结果是否确定。DETERMINISTIC
表示结果是确定的。每次执行存储过程时,相同的输入会得到相同的输出NOT DETERMINISTIC
表示结果是不确定的,相同的输入可能得到不同的输出- 如果没有指定任意一个值,默认为
NOT DETERMINISTIC
{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
:指明子程序使用 SQL 语句的限制CONTAINS SQL
表示当前存储过程的子程序包含 SQL 语句,但是并不包含读写数据的 SQL 语句NO SQL
表示当前存储过程的子程序中不包含任何 SQL 语句READS SQL DATA
表示当前存储过程的子程序中包含读数据的 SQL 语句MODIFIES SQL DATA
表示当前存储过程的子程序中包含写数据的 SQL 语句- 默认情况下,系统会指定为
CONTAINS SQL
SQL SECURITY { DEFINER | INVOKER }
:执行当前存储过程的权限,即指明哪些用户能够执行当前存储过程DEFINER
表示只有当前存储过程的创建者或者定义者才能执行当前存储过程INVOKER
表示拥有当前存储过程的访问权限的用户能够执行当前存储过程
存储过程体中可以有多条 SQL 语句,如果仅仅一条 SQL 语句,则可以省略 BEGIN 和 END
关键字 | 说明 |
---|---|
BEGIN…END |
BEGIN…END 中间包含了多个语句,每个语句都以 ; 号为结束符 |
DECLARE |
DECLARE 用来声明变量,使用的位置在于 BEGIN…END 语句中间,而且需要在其他语句使用之前进行变量的声明 |
SET |
赋值语句,用于对变量进行赋值 |
SELECT… INTO |
把从数据表中查询的结果存放到变量中,也就是为变量赋值 |
DELIMITER |
新的结束标记 |
因为 MySQL 默认的语句结束符号为分号 ;
。为了避免与存储过程中 SQL 语句结束符相冲突,需要使用 DELIMITER 改变存储过程的结束符。DELIMITER //
语句的作用是将MySQL的结束符设置为 //
,并以 END //
结束存储过程。存储过程定义完毕之后再使用 DELIMITER ;
恢复默认结束符。DELIMITER 也可以指定其他符号作为结束符。
1 | DELIMITER $ |
1. 创建存储过程select_all_data(),查看 emps 表的所有数据
1 | DELIMITER $ |
2. 创建存储过程avg_employee_salary(),返回所有员工的平均工资
1 | CREATE PROCEDURE avg_employee_salary () |
3. 创建存储过程show_max_salary(),用来查看“emps”表的最高薪资值
1 | CREATE PROCEDURE show_max_salary() |
4. 创建存储过程show_min_salary(),查看“emps”表的最低薪资值。并将最低薪资通过OUT参数“ms” 输出
1 | DELIMITER // |
5. 创建存储过程show_someone_salary(),查看“emps”表的某个员工的薪资,并用IN参数empname 输入员工姓名
1 | DELIMITER // |
6. 创建存储过程show_someone_salary2(),查看“emps”表的某个员工的薪资,并用IN参数empname 输入员工姓名,用OUT参数empsalary输出员工薪资
1 | CREATE PROCEDURE show_someone_salary2(IN empname VARCHAR(20),OUT empsalary DOUBLE) |
7. 创建存储过程show_mgr_name(),查询某个员工领导的姓名,并用INOUT参数“empname”输入员工姓名,输出领导的姓名
1 | DELIMITER // |
调用存储过程
存储过程必须使用 CALL
语句调用,并且存储过程和数据库相关,如果要执行其他数据库中的存储过程,需要指定数据库名称,例如 CALL dbname.procname。
1 | CALL 存储过程名(实参列表) |
调用in模式的参数
1 | CALL sp1('值'); |
调用out模式的参数
1 | SET @name; |
调用inout模式的参数
1 | SET @name=值; |
案例
1 | DELIMITER // |
1 | -- 调用存储过程 |
存储函数的使用
自定义函数
1 | CREATE FUNCTION 函数名(参数名 参数类型,...) |
调用存储函数
1 | SELECT 函数名(实参列表) |
1. 创建存储函数,名称为email_by_name(),参数定义为空,该函数查询Abel的email,并返回,数据类型为 字符串型
1 | CREATE FUNCTION email_by_name() |
1 | SELECT email_by_name(); |
2. 创建存储函数,名称为email_by_id(),参数传入emp_id,该函数查询emp_id的email,并返回,数据类型 为字符串型
1 | DELIMITER // |
1 | SET @emp_id = 102; |
3. 创建存储函数count_by_id(),参数传入dept_id,该函数查询dept_id部门的员工人数,并返回,数据类型 为整型
1 | DELIMITER // |
1 | SET @dept_id = 50; |
存储函数和存储过程对比
关键字 | 调用语法 | 返回值 | 应用场景 | |
---|---|---|---|---|
存储过程 | PROCEDURE |
CALL 存储过程() |
理解为有0个或 多个 | 一般用于更新 |
存储函数 | FUNCTION |
SELECT 函数 () |
只能是一个 | 一般用于查询结果为一个值并返回时 |
存储过程和函数的查看、修改、删除
查看
1 | -- 1. 使用SHOW CREATE语句查看存储过程和函数的创建信息 |
修改
修改存储过程或函数,不影响存储过程或函数功能,只是修改相关特性。使用 ALTER 语句实现。
1 | ALTER {PROCEDURE | FUNCTION} 存储过程或函数的名 [characteristic ...] |
其中,characteristic 指定存储过程或函数的特性,其取值信息与创建存储过程、函数时的取值信息略有不同。
1 | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } |
CONTAINS SQL
,表示子程序包含 SQL 语句,但不包含读或写数据的语句NO SQL
,表示子程序中不包含 SQL 语句READS SQL DATA
,表示子程序中包含读数据的语句MODIFIES SQL DATA
,表示子程序中包含写数据的语句SQL SECURITY { DEFINER | INVOKER }
,指明谁有权限来执行DEFINER
,表示只有定义者自己才能够执行INVOKER
,表示调用者可以执行
COMMENT 'string'
,表示注释信息
1. 修改存储过程CountProc的定义。将读写权限改为MODIFIES SQL DATA,并指明调用者可以执行
1 | ALTER PROCEDURE CountProc |
1 | SELECT specific_name,sql_data_access,security_type |
2. 修改存储函数CountProc的定义。将读写权限改为READS SQL DATA,并加上注释信息“FIND NAME”
1 | ALTER FUNCTION CountProc |
删除
1 | DROP {PROCEDURE | FUNCTION} [IF EXISTS] 存储过程或函数的名 |