04-存储过程&函数

存储过程

概述

过程化 SQL 块主要有 2 种类型,即命名块和匿名块。前面介绍的是匿名块。匿名块每次执行时都要进行编译,它不能被存储到 DB 中,也不能在其他过程化 SQL 块中调用。过程和函数是命名块,它们被编译后保存在 DB 中,称为“持久性存储模块”,可以被反复调用,运行速度较快。

存储过程是由过程化 SQL 语句书写的过程,这个过程经过编译和优化后存储在 DB 服务器中,因此称它为“存储过程”,使用时只要调用即可。

定义

CREATE OR REPLACE PROCEDURE <存储过程名>([参数1, 参数2, ...]) /* 存储过程首部 */
BEGIN
    /* 存储过程体, 描述该存储过程的操作, 是一组 SQL 语句 */
END
  • 存储过程包括过程首部和过程体
  • 在过程首部,“过程名”是 DB 服务器合法的对象标识
  • 参数列表包含 3 部分:参数模式 参数名 参数类型
    • 举例:IN stuName VARCHAR(20)
    • IN 该参数可作为输入,调用方需要传入值到该参数中
    • OUT 可作为输出,也就是过程返回值
    • INOUT 既可以作为输入,又可以作为输出
  • 过程体 // 如果只有一句话,BEGIN...END 可省
    • 存储过程体中的每条 SQL 语句的结尾要求必须加 ;
    • 存储过程的结尾可以使用 DELIMITER 重新设置

操作

  1. 执行存储过程:CALL <过程名>(实参列表);
  2. 删除存储过程:DROP PROCEDURE <过程名>;
  3. 查看存储过程:SHOW CREATE PROCEDURE <过程名>;

案例

  1. [无参] 插入到 admin 表中 5 条记录
  2. [带 IN 模式] 创建过程实现根据 beauty.name 查询对应的 boy 信息
    CREATE PROCEDURE myPro2(IN beautyName VARCHAR(20))
    BEGIN
        SELECT bo.*
        FROM boys bo
        RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
        WHERE b.name = beautyName;
    END $
    
  3. [带 IN 模式] 创建过程实现用户是否登录成功
    CREATE PROCEDURE myPro3(IN username VARCHAR(20), IN password VARCHAR(20))
    BEGIN
        DECLARE result INT DEFAULT 0; # 声明并初始化
        SELECT COUNT(*) INTO result # 赋值
        FROM admin
        WHERE admin.username = username AND admin.password = password;
        SELECT IF(result>0, '成功', '失败'); # 使用
    END $
    
  4. [带 OUT 模式] 根据 beauty.name,返回对应的 boy.boyName
  5. [带 OUT 模式] 根据 beauty.name,返回对应的 boy.id 和 boy.boyName
    CREATE PROCEDURE myPro5(IN bName VARCHAR(20), OUT id VARCHAR(20), OUT name VARCHAR(20))
    BEGIN
        SELECT bo.id, bo.boyName INTO id, name
        FROM boys bo
        INNER JOIN beauty b ON bo.id = b.boyfriend_id
        WHERE b.name = bName;
    END $
    
  6. [带 INOUT 模式] 传入 a 和 b 两个变量,调用过程后,a 和 b 的值翻倍
  7. 创建过程实现传入一个日期,格式化成:xx 年 xx 月 xx 日并返回
    CREATE PROCEDURE myPro7(IN myDate DATETIME, OUT dateStr VARCHAR(30))
    BEGIN
        SELECT DATE_FORMAT(myDate, '%y 年 %m 月 %d 日') INTO strDate;
    END $
    
  8. 创建过程实现传入 beauty.name,返回:'beauty.name and boys.name' 格式的字符串
    CREATE PROCEDURE myPro8(IN beautyName VARCHAR(20), OUT result VARCHAR(20))
    BEGIN
        SELECT CONCAT(beautyName, ' and ', IFNULL(boyName, 'NULL')) INTO result
        FROM boys bo
        RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
        WHERE b.name = beautyName;
    END $
    
  9. 创建过程实现根据传入的条目数和起始索引,查询 beauty 表的记录
    CREATE PROCEDURE myPro8(IN startIndex INT, IN size INT)
    BEGIN
        SELECT * FROM beauty LIMIT startIndex, size;
    END $
    

函数

函数也称为”自定义函数“,因为是用户自己使用过程化 SQL 设计定义的。函数和存储过程类似,都是持久性存储模块。函数的定义和存储过程也类似,不同之处是函数必须指定返回的类型。

  • 存储过程:可以有 0 个返回,也可以有多个返回,适合做批量插入,批量更新
  • 函数:有且只有 1 个返回,适合做处理数据后返回一个结果

定义

CREATE FUNCTION <函数名>([参数名 参数类型 ...]) RETURNS <类型>
BEGIN
    /* 函数体 */
    return 值;
END $

操作

  1. 调用函数:SELECT 函数名(参数列表)
  2. 删除函数:DROP FUNCTION <函数名>
  3. 查看函数:SHOW CREATE FUNCTION <函数名>

案例

  1. [无参有返回值] 返回 beauty 表记录数
  2. [有参有返回] 根据员工名,返回他的工资
    CREATE FUNCTION func2(empName VARCHAR(20)) RETURNS DOUBLE
    BEGIN
        SET @sal=0; # 定义用户变量
        SELECT salary INTO @sal
        FROM employees WHERE last_name = empName;
        RETURN @sal;
    END $
    
  3. 根据部门名返回该部门的平均工资
    CREATE FUNCTION func3(deptName VARCHAR(20)) RETURNS DOUBLE
    BEGIN
        DECLARE avgSal DOUBLE;
        SELECT AVG(salary) INTO avgSal
        FROM employees e RIGHT JOIN departments d
        ON e.department_id = d.department_id
        WHERE d.department_name = deptName;
        RETURN avgSal;
    END $
    
  4. 创建函数,传入两个 float,返回二者之和
    CREATE FUNCTION func4(num1 FLOAT, num2 FLOAT) RETURNS FLOAT
    BEGIN
        DECLARE sum FLOAT DEFAULT 0;
        SET sum = num1 + num2;
        RETURN sum;
    END $
    
原文地址:https://www.cnblogs.com/liujiaqi1101/p/13622823.html