MySQL从5.0版本开始支持存储过程和函数。存储过程和函数能够将复杂的SQL逻辑封装在一起应用程序无须关注存储过程和函数内部复杂的SQL逻辑,而只需要简单地调用存储过程和函数即可。
存储过程和存储函数的区别在于存储函数是必须有返回值的,而存储过程并没有。

1. 存储过程

存储过程的英文是 Stored Procedure 。它的思想很简单,就是一组经过 预先编译 的 SQL 语句的封装。
分类
存储过程的参数类型可以是IN、OUT和INOUT。根据这点分类如下:
1、没有参数(无参数无返回)
2、仅仅带 IN 类型(有参数无返回)
3、仅仅带 OUT 类型(无参数有返回)
4、既带 IN 又带 OUT(有参数有返回)
5、带 INOUT(有参数有返回)
注意:IN、OUT、INOUT 都可以在一个存储过程中带多个。

  1. CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名 参数类型,...)
  2. [characteristics ...]
  3. BEGIN
  4. 存储过程体
  5. END

参数说明
1、参数前面的符号的意思

  • IN :当前参数为输入参数,也就是表示入参;存储过程只是读取这个参数的值。如果没有定义参数种类, 默认就是 IN ,表示输入参数。
  • OUT :当前参数为输出参数,也就是表示出参;执行完成之后,调用这个存储过程的客户端或者应用程序就可以读取这个参数返回的值了。
  • INOUT :当前参数既可以为输入参数,也可以为输出参数。

2、形参类型可以是 MySQL数据库中的任意类型。
3、 characteristics 表示创建存储过程时指定的对存储过程的约束条件,其取值信息如下:

  • LANGUAGE SQL
    存储过程语言,默认是sql,说明存储过程中使用的是sql语言编写的,暂时只支持sql,后续可能会支持其他语言
  • NOT DETERMINISTIC
    是否确定性的输入就是确定性的输出,默认是NOT DETERMINISTIC,只对于同样的输入,输出也是一样的,当前这个值还没有使用
  • CONTAINS SQL
    提供子程序使用数据的内在信息,这些特征值目前提供给服务器,并没有根据这些特征值来约束过程实际使用数据的情况,说白了就是没有使用的
    包括以下四种选择
    1.CONTAINS SQL表示子程序不包含读或者写数据的语句
    2.NO SQL 表示子程序不包含sql
    3.READS SQL DATA 表示子程序包含读数据的语句,但是不包含写数据的语句
    4.MODIFIES SQL DATA 表示子程序包含写数据的语句。
  • SQL SECURITY DEFINER
    用来指定存储过程是使用创建者的许可来执行,还是执行者的许可来执行,默认值是DEFINER
    DEFINER 创建者的身份来调用,对于当前用户来说:如果执行存储过程的权限,且创建者有访问表的权限,当前用户可以成功执行过程的调用的
    说白了就是当前用户调用存储过程,存储过程执行的具体操作是借助定义存储过程的user的权限执行的。
    INVOKER 调用者的身份来执行,对于当前用户来说:如果执行存储过程的权限,以当前身份去访问表,如果当前身份没有访问表的权限,即便是有执行过程的权限,仍然是无法成功执行过程的调用的。
    说白了就是当前用户调用存储过程,只有当前用户有执行存储过程中涉及的对象的操作的权限的时候,才能成功执行。
  • COMMENT ‘’
    存储过程的注释性信息写在COMMENT里面,这里只能是单行文本,多行文本会被移除到回车换行等,

DELIMITER
因为MySQL默认的语句结束符号为分号‘;’。为了避免与存储过程中SQL语句结束符相冲突,需要使用DELIMITER改变存储过程的结束符。

DELEMITER $

示例

DELIMITER $
CREATE PROCEDURE `select_all_emp`()
BEGIN
    SELECT * FROM test.`employees`;
END $
DELIMITER ;

#调用存储过程
CALL select_all_emp()

OUT的使用

DELIMITER $
CREATE  PROCEDURE `select_max_salary_out`(OUT ms DOUBLE)
BEGIN 
    SELECT MAX(salary) INTO ms FROM test.`employees`;
END $
DELIMITER ;

CALL select_max_salary_into(@ms)

SELECT@ms

IN的使用

DELIMITER $
CREATE PROCEDURE `select_emp_in_salary`(IN salary_in DOUBLE)
BEGIN
    SELECT * FROM test.`employees` WHERE salary=salary_in;
END $
DELIMITER ;

CALL select_emp_in_salary(2400)
DELIMITER $
CREATE PROCEDURE select_emp_in_out_salary(IN `name` VARCHAR(20),OUT salary_out DOUBLE)
BEGIN
    SELECT salary INTO salary_out FROM employees WHERE last_name=`name`;
END $
DELIMITER ;

CALL select_emp_in_out_salary('Abel',@a)
SELECT @a

INOUT的使用

DELIMITER $
CREATE PROCEDURE select_manager_name_by_emp_name(INOUT `name` VARCHAR(20))
BEGIN 
    SELECT e1.last_name INTO `name` FROM employees AS e1,employees AS e2
    WHERE e2.manager_id=e1.employee_id AND e2.last_name=`name`;
END $
DELIMITER ; 

SET @name='Abel'
CALL select_manager_name_by_emp_name(@name)

SELECT @name

2. 函数

CREATE FUNCTION 函数名(参数名 参数类型,...)
RETURNS 返回值类型
[characteristics ...]
BEGIN
函数体  #函数体中肯定有 RETURN 语句
END

image.png
方式1:
加上必要的函数特性“[NOT] DETERMINISTIC”和“{CONTAINS SQL | NO SQL | READS SQL DATA |MODIFIES SQL DATA}”
方式2:
SET GLOBAL log_bin_trust_function_creators = 1;

DELIMITER $
CREATE FUNCTION select_email_by_name()
RETURNS VARCHAR(20)
BEGIN
    RETURN (SELECT email FROM `employees` WHERE last_name='Abel');
END $
DELIMITER ;

SELECT select_email_by_name();
DELIMITER //
CREATE FUNCTION email_by_id(emp_id INT)
RETURNS VARCHAR(25)
BEGIN
    RETURN (SELECT email FROM employees WHERE employee_id = emp_id);
END //
DELIMITER ;

3. 对比存储过程和函数

image.png
存储函数可以放在查询语句中使用,存储过程不行

4. 过程和函数的查看,修改,删除

使用SHOW CREATE语句查看存储过程和函数的创建信息

SHOW CREATE {PROCEDURE | FUNCTION} 存储过程名或函数名

使用SHOW STATUS语句查看存储过程和函数的状态信息

SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']

从information_schema.Routines表中查看存储过程和函数的信息

SELECT * FROM information_schema.Routines
WHERE ROUTINE_NAME='存储过程或函数的名' [AND ROUTINE_TYPE = {'PROCEDURE|FUNCTION'}];

修改
修改存储过程或函数,不影响存储过程或函数功能,只是修改相关特性。使用ALTER语句实现。

ALTER {PROCEDURE | FUNCTION} 存储过程或函数的名 [characteristic ...]

其中,characteristic指定存储过程或函数的特性,其取值信息与创建存储过程、函数时的取值信息略有不同。

{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
  1. CONTAINS SQL ,表示子程序包含SQL语句,但不包含读或写数据的语句。
  2. NO SQL ,表示子程序中不包含SQL语句。
  3. READS SQL DATA ,表示子程序中包含读数据的语句。
  4. MODIFIES SQL DATA ,表示子程序中包含写数据的语句。
  5. SQL SECURITY { DEFINER | INVOKER } ,指明谁有权限来执行。
    1. DEFINER ,表示只有定义者自己才能够执行。
    2. INVOKER ,表示调用者可以执行。
  6. COMMENT ‘string’ ,表示注释信息。

删除

DROP {PROCEDURE | FUNCTION} [IF EXISTS] 存储过程或函数的名