当前位置: 首页 > news >正文

思途SQL学习 0729

在MySQL中,函数主要分为两大类:内置函数和用户自定义函数(UDF)。

内置函数

MySQL提供了丰富的内置函数来帮助执行各种操作,比如数学运算、字符串处理、日期时间处理等。使用这些函数非常直接,你只需要按照正确的语法在你的SQL查询中调用它们即可。例如:

  • 数学函数:ABS(-5) 返回 5。
  • 字符串函数:UPPER('hello') 返回 'HELLO'。
  • 日期函数:CURDATE() 返回当前日期。

用户自定义函数(UDF)

如果你需要的功能不能通过内置函数实现,你可以创建自己的函数。这通常涉及到存储过程或函数的编写。这里我们关注于如何创建一个简单的标量函数,它可以接受输入参数并返回一个结果。


一、MySQL 函数的本质

在 MySQL 中,函数(Function) 是一种可重复使用的、带有逻辑的数据库对象,它的核心特点是:

  1. 必须返回一个值:这是函数与存储过程最根本的区别。函数通过 RETURN 语句返回一个结果。
  2. 可以接受参数:函数可以定义输入参数(IN 参数,这是默认的)。
  3. 可以在 SQL 语句中调用:函数最强大的地方在于它能像 SUM()UPPER() 这样的内置函数一样,被嵌入到 SELECTWHEREINSERTUPDATE 等 SQL 语句中使用。
  4. 有确定性(Deterministic)属性:如果函数对于相同的输入总是返回相同的结果,可以声明为 DETERMINISTIC,这有助于查询优化器进行优化。

二、函数的基本语法结构

DELIMITER $$CREATE FUNCTION function_name (parameter1 datatype, parameter2 datatype, ...)
RETURNS return_datatype
[DETERMINISTIC | NOT DETERMINISTIC] -- 可选,是否确定性
READS SQL DATA | MODIFIES SQL DATA | CONTAINS SQL | NO SQL -- 可选,数据访问特性
BEGIN-- 函数体:声明变量、控制流、SQL 语句等DECLARE variable_name datatype DEFAULT value;-- ... 逻辑处理 ...RETURN return_value; -- 必须有,且返回值类型与声明一致
END$$DELIMITER ;

三、对例子进行详细解析

1. 最简单的函数:f_hello()
CREATE FUNCTION `f_hello`() RETURNS varchar(100) CHARSET utf8mb3
BEGINRETURN 'Hello World';
END
  • 特点
    • 无参数。
    • 返回一个固定的字符串 varchar(100)
    • 可以直接在 SELECT 中调用:SELECT f_hello(); -> 输出 Hello World
  • 用途:演示基本语法,或作为占位符。
2. 带计算逻辑的函数:f_jiecheng(n)
CREATE FUNCTION `f_jiecheng`(n int) RETURNS bigint
BEGIN declare result bigint DEFAULT 1; declare i int default 1;WHILE i <= n DOIF i % 7 <> 0 THEN -- 注意:这里是排除 7 的倍数SET result = result * i;END IF;SET i = i + 1;END WHILE;RETURN result;
END
  • 特点
    • 接受一个 INT 类型的参数 n
    • 使用 DECLARE 声明了局部变量 result 和 i
    • 包含了循环 (WHILE) 和条件判断 (IF)。
    • 返回一个 BIGINT 类型的计算结果。
  • 调用SELECT f_jiecheng(5); 计算的是 1*2*3*4*5(因为 7>5,所以不影响),返回 120
  • 注意:这个函数计算的不是标准阶乘(排除了 7 的倍数),但逻辑清晰。
3. 带 SQL 查询和游标的函数:f_get_avg_study_point(classid)
CREATE FUNCTION `f_get_avg_study_point`(classid int) RETURNS float
BEGINDECLARE endLoop INT DEFAULT 0;DECLARE point int DEFAULT 0;DECLARE sum int DEFAULT 0;DECLARE amount int;DECLARE cur CURSOR FOR SELECT study_points from t_students where class_id = classid;DECLARE CONTINUE HANDLER FOR NOT FOUND set endLoop = 1;OPEN cur;FETCH cur INTO point;WHILE endLoop < 1 do SET sum = sum + point;FETCH cur INTO point;END WHILE;CLOSE cur;SELECT count(*) INTO amount from t_students where class_id = classid;RETURN ROUND(sum/amount,2); 
END
  • 特点
    • 接受班级 ID 作为参数。
    • 使用 游标(CURSOR) 遍历 t_students 表中指定班级的学生学分。
    • 使用 DECLARE CONTINUE HANDLER FOR NOT FOUND 来捕获游标遍历结束的信号(NOT FOUND),并设置标志 endLoop=1 来退出循环。
    • 手动累加学分 (sum),再查询学生总数 (amount),最后计算平均值。
    • 使用 ROUND() 函数四舍五入到 2 位小数。
4. 嵌套查询和条件判断的函数:f_get_level(id)
CREATE FUNCTION `f_get_level`(id int) RETURNS char(2) CHARSET utf8mb4 COLLATE utf8mb4_general_ci
BEGINDECLARE avg_iq float; DECLARE current_iq int;-- 查询该学生所在班级的平均智商SELECT avg(iq) INTO avg_iq FROM t_student where class_id = (SELECT class_id from t_student t where t.id = id);-- 查询该学生的智商SELECT iq INTO current_iq from t_student t1 where t1.id = id;IF current_iq > avg_iq THENRETURN '及格';ELSERETURN '淘汰';END IF;
END
  • 特点
    • 接受学生 ID。
    • 包含子查询:先查出该学生所属的 class_id,再用这个 class_id 去查全班的平均智商。
    • 使用 SELECT ... INTO variable 将查询结果赋值给局部变量。
    • 使用 IF...ELSE...END IF 进行条件判断。
    • 返回一个 CHAR(2) 类型的字符串('及格' 或 '淘汰')。
  • 调用SELECT f_get_level(101); 返回学生 ID 为 101 的等级。
  • 优化思考:这个查询可以优化为一次连接查询,但作为函数逻辑是清晰的。

5.存储过程 p_delete_student() - 基于函数判断的删除操作
  • 核心逻辑
    1. 使用游标 cur 遍历 t_student 表中所有学生 ID (pid)。
    2. 对每个 pid,调用函数 f_get_level(pid) 来判断该学生是否“淘汰”。
    3. 如果函数返回 '淘汰',则执行 DELETE 语句删除该学生记录。
  • 关键点
    • 函数调用SELECT f_get_level(pid) INTO a; 这是函数在过程内部被调用的典型方式。函数 f_get_level 的返回值被赋给了变量 a
    • DML 操作:过程内部执行了 DELETE 语句,这只能在存储过程中实现,不能在函数中实现。
    • 游标与循环:展示了如何使用游标和 WHILE 循环来逐行处理查询结果。
    • 错误处理DECLARE CONTINUE HANDLER FOR NOT FOUND SET con = 1; 处理了游标 FETCH 时没有更多数据的情况,这是游标编程的标准做法。
  • 为什么是过程? 因为它执行了数据修改(DELETE),并且没有单一的返回值,而是执行一系列动作。

综合梳理:MySQL 函数与存储过程的核心要点

特性/方面函数 (FUNCTION)存储过程 (PROCEDURE)
定义关键字CREATE FUNCTIONCREATE PROCEDURE
返回值必须 有 RETURNS 子句和 RETURN 语句。返回单一值。没有 RETURNS 子句。可通过 OUT/INOUT 参数返回多个值,或不返回。
调用方式可在 SQL 表达式中 调用:SELECT func_name(...), column FROM table; 或 WHERE func_name(...) = value;使用 CALL proc_name(...); 语句独立调用
参数类型默认且仅支持 IN 参数(输入)。支持 IN (输入), OUT (输出), INOUT (输入输出)。
DML 操作禁止 执行 INSERTUPDATEDELETE 等修改数据的语句。允许 执行任何 DML 语句。
事务控制不能包含 COMMIT 或 ROLLBACK可以包含 COMMIT 或 ROLLBACK 来显式管理事务。
主要用途数据计算、转换、格式化、复杂条件判断(返回结果)。作为 SQL 语句的一部分。执行复杂的业务逻辑、批处理任务、数据清理、报表生成、调用多个函数/过程等。
你的例子f_hellof_jiechengf_get_avg_study_pointf_get_levelf_sum_unilp_delete_studentproc_gen_student_score
函数调用可在自身或其他过程/函数中被调用(需注意限制)。可在自身或其他过程/函数中被调用(用 CALL)。
错误处理可使用 DECLARE ... HANDLER可使用 DECLARE ... HANDLER
游标可以 使用游标(如 f_get_avg_study_point),但不能在游标循环内执行 DML。可以 使用游标,并在循环内执行 DML(如 p_delete_studentproc_gen_student_score)。

游标(Cursor) 在数据库管理系统中是一种用于遍历查询结果集的数据库对象。它允许应用程序或用户逐行处理查询返回的数据,而不是一次性将所有数据加载到内存中。这对于处理大量数据或者需要对每一行执行特定操作的情况特别有用。

游标的基本概念

  1. 声明游标:定义一个游标,并将其与一个查询关联起来。
  2. 打开游标:执行与游标关联的查询,并准备好获取数据。
  3. 提取数据:从查询结果集中逐行获取数据。
  4. 关闭游标:完成数据处理后,关闭游标释放资源。

MySQL中的游标使用

在MySQL中,游标通常在存储过程或函数内部使用。以下是一个基本的游标操作流程:

-- 声明变量
DECLARE var_name datatype;-- 声明游标
DECLARE cur_name CURSOR FOR select_statement;-- 声明继续处理器,当SQL语句没有找到更多行时设置标志位
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;-- 打开游标
OPEN cur_name;-- 循环提取数据
read_loop: LOOPFETCH cur_name INTO var_name;IF done THENLEAVE read_loop;END IF;-- 处理逻辑...
END LOOP;-- 关闭游标
CLOSE cur_name;

关键点说明

  • DECLARE CURSOR:定义游标并指定与其关联的SELECT语句。
  • OPEN:执行游标对应的查询,并使游标指向结果集的第一行之前。
  • FETCH:将当前行的数据提取到指定的变量中,并将游标向前移动到下一行。
  • CONTINUE HANDLER:定义了当没有更多行可供读取时的行为(例如设置一个标志变量done1)。
  • CLOSE:关闭游标,释放相关资源。

http://www.lryc.cn/news/603303.html

相关文章:

  • 【CUDA显存不足的问题】
  • ironSource Ads Bidding 现已正式加入TopOn 聚合平台
  • 博弈论03——混合纳什均衡的收益求法
  • 【Linux入坑(一)—全志T133开发板适配欣瑞达LVDS 7寸(800*480)屏幕】
  • 函数对象 vs 函数指针 vs lambda:该用哪个才高效?
  • python学习DAY26打卡
  • Java高级技术知识点
  • GitLab的安装及使用
  • 路由器路由协议详解:从 RIP 到 OSPF 的技术演进
  • 理解Transformer解码器
  • 【术语扫盲】MCU与MPU
  • 《HCIA-Datacom 认证》希赛三色笔记:Vlan间三层通信过程解析
  • 高级08-Java JVM调优:优化你的Java应用
  • 面向对象系统的单元测试层次
  • 医疗AI新基建:MCP与A2A协议的破局与前瞻
  • MySQL——MVCC
  • Django自带的加密算法
  • 汇总10个高质量免费AI生成论文网站,支持GPT4.0和DeepSeek-R1
  • 云端文档管理新纪元:Paperless-ngx与cpolar打造的无边界文件生态
  • PHP性能优化与高并发处理:从基础到高级实践
  • 深入理解Java Map的entrySet()方法
  • VLA--Gemini Robotics On-Device: 将AI带到本地机器人设备上
  • 在WSL中配置VS Code C++开发环境完整教程
  • LeetCode 1616.分割两个字符串得到回文串
  • 【21】C# 窗体应用WinForm ——图片框PictureBox属性、方法、实例应用
  • 【MySQL学习|黑马笔记|Day2】SQL|DML、DGL、DCL,函数,约束
  • redis得到shell的几种方法
  • 搭建专属AI聊天网站:NextChat + 蓝耘MaaS平台完整部署指南
  • 《C++初阶之STL》【list容器:详解 + 实现】
  • 夯实家庭基石本质上是一场“缓慢的革命”