第十五章:存储过程与函数

第十五章:存储过程与函数

15.1:存储过程概述

  1. 理解

    • 含义:

      存储过程的英文是Stored Procedure。它的思想很简单,就是一组经过预先编译SQL语句的封装。

    • 执行过程:

      ​ 存储过程预先存储在MySQL服务器上,需要执行的时候,客户端只需要向服务端发出调用存储过程的命令,服务端就可以把预先存储好的这一系列SQL语句全部执行。

    • 好处

      1. 简化操作,提高了sql语句的重要性,减少了开发程序员的压力。
      2. 减少操作过程中的失误,提高效率。
      3. 减少网络删除量(客户端不需要把所有的SQL语句通过网络发给服务器)。
      4. 减少了SQL语句暴露在网上的风险,也提高了数据查询的安全性。
  2. 分类

    存储过程的参数类型可以是INOUTINOUT。根据这点分类如下:

    • 没有参数(无参数无返回)
    • 仅仅带IN类型(有参数无返回)
    • 仅仅带OUT类型(无参数有返回)
    • 既带IN又带OUT(有参数无返回)
    • INOUT(有参数有返回)

    注意:INOUTINOUT都可以在一个存储过程中带多个。

15.2:创建存储过程

  1. 语法分析

    • 语法

      CREATE PROCEDURE 存储过程名(IN | OUT | INOUT 参数名 参数类型, ....)
      [characteristics ...]
      BEGIN
      	存储过程体
      END
      
    • 参数前面的符号说明

      1. IN:当前参数为输入参数,也就是表示入参。

        存储过程只是读取这个参数的值。如果没有定义参数种类,默认就是IN,表表示输入参数。

      2. OUT:当前参数为输出参数,也就是表示出参。

        执行完成之后,调用这个存储过程的客户端或者应用程序就可以读取这个参数返回的值了。

      3. INOUT:当前参数既可以输入参数,也可以输出参数。

    • 形参类型可以是MySQL数据库中的任意类型。

    • characteristics表示创建存储过程时指定的存储过程的约束条件,其取值信息如下:

      1. LANGUAGE SQL:说明存储过程执行体是由SQL语句组成的,当前系统支持的语言为SQL
      2. [NOT] DETERMINISTIC:指明存储过程执行的结果是否确定。
        • DETERMINISTIC表示结果确定的,每次执行存储过程时,相同的输入会得到相同的输出。
        • NOT DETERMINISTIC表示结果是不确定的,相同的输入可能得到不同的输出。若没有指定任意一个值,默认为不确定的
      3. 指明子程序使用SQL语句的限制:{CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
        • CONTAINS SQL:表示当前存储过程的子程序包含SQL语句,但是并不包含读写数据的SQL语句。系统默认指定情况。
        • NO SQL表示当前存储过程的子程序中不包含任何SQL语句。
        • READS SQL DATA:表示当前存储过程的子程序中包含读数据的SQL语句。
        • MODIFIES SQL DATA:表示当前存储过程的子程序中包含写数据的SQL语句。
      4. SQL SECURITY { DEFINER | INVOKER }:执行当前存储过程的权限,即指明哪些用户能够执行当前存储过程。
        • DEFINER :表示只有当前存储过程的创建者或者定义者才能执行当前存储过程。没有设置系统默认指定。
        • INVOKER :表示拥有当前存储过程的访问权限的用户能够执行当前存储过程。
      5. COMMENT 'String':注释信息,可以用来描述存储过程。
    • 存储过程体中可以有多条SQL语句,如果仅仅一条SQL语句,则可以省略BEGINEND

    • 需要设置新的结束标志

      DELIMITER 新的结束标记
      

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

  2. 代码举例

    #类型1:无参数无返回值
    #举例1:创建存储过程select_all_data(),查看 employees 表的所有数据
    DELIMITER $
    
    CREATE PROCEDURE select_all_data()
    BEGIN
    	SELECT * FROM employees;
    END $
    
    DELIMITER ;
    #2. 存储过程的调用
    CALL select_all_data();
    
    #类型2:带 OUT
    #举例2:创建存储过程show_min_salary(),查看“emps”表的最低薪资值。并将最低薪资通过OUT参数“ms”输出
    DESC employees;
    
    DELIMITER //
    
    CREATE PROCEDURE show_min_salary(OUT ms DOUBLE)
    BEGIN
    	SELECT MIN(salary) INTO ms
    	FROM employees;
    END //
    
    DELIMITER ;
    #调用
    CALL show_min_salary(@ms);
    SELECT @ms;
    
    #类型3:带 IN
    #举例3:创建存储过程show_someone_salary(),查看“emps”表的某个员工的薪资,并用IN参数empname输入员工姓名。
    DELIMITER //
    
    CREATE PROCEDURE show_someone_salary(IN empname VARCHAR(20))
    BEGIN
    	SELECT salary FROM employees
    	WHERE last_name = empname;
    END //
    
    DELIMITER;
    #调用方式1
    CALL show_someone_salary('Abel');
    #调用方式2
    SET @empname := 'Abel';
    CALL show_someone_salary(@empname);
    
    #类型4:带 IN 和 OUT
    #举例4:创建存储过程show_someone_salary2(),查看“emps”表的某个员工的薪资,并用IN参数empname输入员工姓名,用OUT参数empsalary输出员工薪资。
    DELIMITER //
    
    CREATE PROCEDURE show_someone_salary2(IN empname VARCHAR(20), OUT empsalary DECIMAL(10, 2))
    BEGIN
    	SELECT salary INTO empsalary
    	FROM employees
    	WHERE last_name = empname;
    END // 
    
    DELIMITER;
    #调用
    SET @empname = 'Abel';
    CALL show_someone_salary2(@empname, @empsalary);
    SELECT @empsalary;
    
    #类型5:带 INOUT
    #举例5:创建存储过程show_mgr_name(),查询某个员工领导的姓名,并用INOUT参数“empname”输入员工姓名,输出领导的姓名。
    
    DELIMITER $
    
    CREATE PROCEDURE show_mgr_name(INOUT empname VARCHAR(25))
    BEGIN
    	SELECT last_name INTO empname
    	FROM employees
    	WHERE employee_id = (
    		SELECT manager_id
    		FROM employees
    		WHERE last_name = empname
    	);
    END $
    
    DELIMITER;
    #调用
    SET @empname := 'Abel';
    CALL show_mgr_name(@empname);
    SELECT @empname;
    

15.3:存储函数的使用

  1. 语法分析

    CREATE FUNCTION 函数名(参数名 参数类型, ....)
    RETURNS 返回值类型
    [characteristics ...]
    BEGIN
    	函数体 
    	RETURN 返回值或表达值
    END
    
    • 参数列表:指定参数为INOUTINOUT只对RPOCEDURE是合法的,FUNCTION中总是默认为IN参数。

    • RETURNS type语句表示函数返回数据的类型。

      RETURNS子句只能对FUNCTION做指定,对函数而言这是强制的。它用来指定函数的返回值类型,而且函数体必须包含一个RETUEN value语句。

    • characteristic创建函数时指定的对函数的约束。取值与创建存储过程相同。

    • 函数体也可以用BEGIN ... END来表示SQL代码的开始和结束。如果函数体只有一条语句,也可以省略BEGIN ... END

  2. 调用存储函数

    ​ 在MySQL中,存储函数的使用方法与MySQL内部函数的使用方法是一样。换言之,用户自己定义的存储函数与MySQL内部函数是一个性质的。区别在于,存储函数是用户自己定义的,而内部函数是MySQL开发者定义的。

    SELECT 函数名(实参列表)
    
  3. 代码举例

    # 举例1:创建存储函数,名称为email_by_name(),参数定义为空,该函数查询Abel的email,并返回,数据类型为字符串型。
    DELIMITER //
    CREATE FUNCTION email_by_name()
    RETURNS VARCHAR(25)
    # 解决创建存储函数报“you might want to use the less safe log_bin_trust_function_creators variable”错方式一
    	DETERMINISTIC
    	CONTAINS SQL
    	READS SQL DATA
    BEGIN
    	RETURN (SELECT email FROM employees WHERE last_name = 'Abel');
    END //
    DELIMITER;
    #调用
    SELECT email_by_name();
    
    #举例2:创建存储函数,名称为email_by_id(),参数传入emp_id,该函数查询emp_id的email,并返回,数据类型为字符串型。
    #解决创建存储函数报“you might want to use the less safe log_bin_trust_function_creators variable”错方式二
    SET GLOBAL log_bin_trust_function_creators = 1;
    
    # 声明函数
    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;
    #调用
    SELECT email_by_id(101);
    SET @emp_id := 102;
    SELECT email_by_id(@emp_id);
    
  4. 对比存储函数和存储过程

    关键字 调用语法 返回值 应用场景
    存储过程 RPOCEDURE CALL存储过程() 理解为有0个或多个 一般用于更新
    存储函数 FUNCTION SELECT函数() 只能是一个 一般用于查询结果为一个值并返回时

    ​ 此外,存储函数可以放在查询语句中使用,存储过程不行。反之,存储过程的功能更加强大,包括能够执行对表的操作(比如创建表、删除表等)和事物操作,这些功能是存储函数不具备的。

15.4:存储过程和函数的查询、修改、删除

  1. 查看

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

      # 查看存储过程
      SHOW CREATE PROCEDURE show_mgr_name;
      # 查看存储函数
      SHOW CREATE FUNCTION count_by_id;
      
    • 使用SHOW STATUS语句查看存储过程和函数的状态信息

      # 查看所有的存储过程和存储函数
      SHOW PROCEDURE STATUS;
      SHOW FUNCTION STATUS;
      # 查看其中一个或多个的存储过程和存储函数
      SHOW PROCEDURE STATUS LIKE 'show_max_salary';
      SHOW FUNCTION STATUS LIKE 'email_by_id';
      
    • information_schema.Routines表中查看存储过程和函数的信息

      # 查看存储过程
      SELECT * FROM information_schema.`ROUTINES`
      WHERE ROUTINE_NAME = 'show_min_salary' AND ROUTINE_TYPE = 'PROCEDURE';
      # 查看存储函数
      SELECT * FROM information_schema.ROUTINES
      WHERE ROUTINE_NAME = 'email_by_id' AND ROUTINE_TYPE = 'FUNCTION';
      
  2. 修改

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

    # 语法
    ALTER {PROCEDURE | FUNCTION} 存储过程或函数的名 [characteristic ...]
    # 举例
    ALTER PROCEDURE show_max_salary
    SQL SECURITY INVOKER
    COMMENT '查询最高工资';
    
  3. 删除

    删除存储过程或函数,可以使用DROP语句,其语法结构如下:

    DROP {PROCEDURE | FUNCTION} [IF EXISTS] 存储过程或函数的名
    # 举例
    DROP FUNCTION IF EXISTS count_by_id;
    DROP PROCEDURE IF EXISTS show_min_salary;
    
  4. 存储过程的优点和缺点

    • 优点
      1. 存储过程可以一次编译多次使用。
      2. 可以减少开发工作量。
      3. 存储过程的安全性强。
      4. 可以减少网络传输。
      5. 良好的封装性。
    • 缺点
      1. 可移植性差。
      2. 调试困难。
      3. 存储过程的版本管理很困难。
      4. 它不适合高并发的场景。

你可能感兴趣的:(MySQL,数据库,sql,mysql)