一、存储函数 vs. 存储过程

 特性  存储函数 (FUNCTION)  存储过程 (PROCEDURE)

返回值  必须通过 `RETURN` 语句返回一个值  可以通过 `OUT`/`INOUT` 参数返回零个或多个值,但没有直接返回值

核心用途  计算并返回一个结果  执行复杂的业务逻辑操作(如增删改、事务管理等)

调用方式  在 SQL 语句中直接调用(如 `SELECT`)  使用 `CALL` 语句调用

参数类型  参数默认为 `IN`(输入参数),不能有 `OUT`/`INOUT` 参数  参数可以是 `IN`, `OUT`, `INOUT`

 

二、创建存储函数 (CREATE FUNCTION)

基本语法:

CREATE FUNCTION function_name ([parameter_list])
RETURNS data_type
[characteristic ...]
routine_body

`function_name`: 存储函数的名称。名称应唯一,推荐使用 `func_` 前缀。

`parameter_list`: 参数列表。格式为:`[IN] param_name param_type`。因为参数只能是输入的,所以 `IN` 关键字通常可以省略。

       `param_name`: 参数名。

       `param_type`: 参数的数据类型(如 `INT`, `VARCHAR(255)`)。

`RETURNS data_type`: 必须声明函数返回值的数据类型。

`characteristic`: 函数的特性(可选),与存储过程相同。常用选项:

       `DETERMINISTIC`:表示函数是“确定性”的,即相同的输入总是产生相同的输出(如数学函数)。如果函数使用了`NOW()`等非确定性函数,则不应使用此选项。

       `NOT DETERMINISTIC`:表示函数是“非确定性”的(默认)。

       `COMMENT 'string'`:函数的注释说明。

`routine_body`: 函数体,由 `BEGIN ... END` 包裹的有效 SQL 语句集合。其中必须包含至少一个 `RETURN value` 语句。

 

三、创建示例与步骤

创建函数时,通常需要临时修改分隔符,以避免函数体中的 `;` 被误认为是整个 SQL 语句的结束。

1.  选择数据库:

    USE test;

2.  修改分隔符 (通常改为 `//` 或 `$$`):

    DELIMITER //

3.  创建函数:

    CREATE FUNCTION func_student(std_id INT)

    RETURNS VARCHAR(20)

    COMMENT '根据学生ID查询姓名'

    BEGIN

         声明一个变量来存储结果

        DECLARE student_name VARCHAR(20);

         查询并将结果赋值给变量

        SELECT name INTO student_name

        FROM tb_student

        WHERE id = std_id;

         返回结果

        RETURN(student_name);

    END //

4.  恢复分隔符:

    DELIMITER ;

示例 2:计算两个数的和(更简单的例子)

DELIMITER //
CREATE FUNCTION func_add(a INT, b INT)
RETURNS INT
DETERMINISTIC
BEGIN
    RETURN a + b;
END //
DELIMITER ;

 

四、调用存储函数

存储函数可以在任何允许使用表达式的地方调用,最常用于 `SELECT` 语句:

 调用示例1的函数

SELECT func_student(1);

 调用示例2的函数

SELECT func_add(5, 3); -- 返回 8

 在查询中使用

SELECT id, name, func_add(score, 10) AS new_score FROM tb_student;

 

五、管理存储函数

1.  查看函数

       查看所有函数状态(模糊匹配):

        SHOW FUNCTION STATUS LIKE 'func_%';

       查看某个函数的定义:

        SHOW CREATE FUNCTION func_student;

       从信息模式中查询:

        SELECT * FROM information_schema.ROUTINES

        WHERE ROUTINE_TYPE = 'FUNCTION' AND ROUTINE_NAME = 'func_student';

 

2.  修改函数

    使用 `ALTER FUNCTION` 语句主要用来修改注释、特性等元数据,不能修改函数体或参数。要修改这些,必须先 `DROP` 再 `CREATE`。

    ALTER FUNCTION func_student COMMENT 'This is a new comment';

 

3.  删除函数

    DROP FUNCTION IF EXISTS func_student;

    `IF EXISTS` 是可选的,用于防止因函数不存在而报错。

 

六、重要注意事项

1.  权限:创建存储函数需要 `CREATE ROUTINE` 权限。

2.  确定性:如果函数被标记为 `DETERMINISTIC` 但它实际上不是,可能会导致优化器做出错误的决策,结果不可预测。

3.  RETURN 类型:`RETURN` 语句返回的值必须与 `RETURNS` 子句声明的类型兼容,否则会被强制转换。

4.  函数体限制:存储函数中不能使用执行显式或隐式提交(`COMMIT`)或回滚(`ROLLBACK`)的 SQL 语句。它们通常也不允许修改数据库数据(即不允许有 `INSERT`, `UPDATE`, `DELETE` 等语句),主要用于计算。这与存储过程不同。

点赞(1)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)