MySQL函数介绍
MySQL自定义函数(Function)是一组预编译的SQL语句集合,它们被存储在数据库中并可重复使用。函数接受输入参数,执行特定操作,并且必须返回一个单一值。
函数的基本特点
-
封装性:将多个SQL操作封装为一个单元
-
重用性:能在多个SQL语句中重复调用
-
简化操作:使复杂的操作变得简单
-
返回单一值:必须且只能返回一个值
-
可在SQL表达式中使用:可以直接在SELECT语句中使用
函数与存储过程的区别
函数和存储过程都是MySQL中的程序化对象,但它们在用途、语法和行为上有明显区别。
特性 | 函数(Function) | 存储过程(Procedure) |
---|---|---|
返回值 | 必须返回一个单一值 | 可以返回多个值,也可以不返回值 |
调用方式 | 可以在SQL语句中直接调用 | 使用CALL语句单独调用 |
使用场景 | 计算和数据转换 | 执行复杂的业务逻辑和事务 |
参数类型 | 只支持输入参数(IN) | 支持输入(IN)、输出(OUT)和输入输出(INOUT)参数 |
事务操作 | 通常不在函数中进行事务操作 | 经常包含事务处理 |
数据修改 | 一般不建议在函数中修改数据 | 可以执行数据修改操作 |
需要获取学生的平均分数:
DELIMITER $$ CREATE PROCEDURE get_student_avg_proc(IN student_id INT, OUT avg_score DECIMAL(5, 2)) BEGIN SELECT AVG(score) INTO avg_score FROM t_score WHERE sid = student_id; SET avg_score = IFNULL(avg_score, 0); END $$ DELIMITER ; -- 调用方式: SET @avg = 0; CALL get_student_avg_proc(1001, @avg); SELECT @avg AS 平均分;
DELIMITER $$ CREATE FUNCTION get_student_avg(student_id INT) RETURNS DECIMAL(5, 2) READS SQL DATA BEGIN DECLARE avg_score DECIMAL(5, 2); SELECT AVG(score) INTO avg_score FROM t_score WHERE sid = student_id; RETURN IFNULL(avg_score, 0); END $$ DELIMITER ; -- 调用方式: SELECT sid, sname, get_student_avg(sid) AS 平均分 FROM t_student;
使用函数的场景:
-
需要在SELECT语句中使用计算结果
-
需要返回单一值的数据转换或计算
-
查询操作,不涉及数据修改
-
需要在WHERE或ORDER BY子句中使用
使用存储过程的场景:
-
执行包含多个步骤的复杂业务逻辑
-
需要返回多个结果或使用结果集
-
需要执行数据修改操作(INSERT/UPDATE/DELETE)
-
需要进行事务处理
-
需要错误处理和异常捕获
MySQL函数创建语法
基本语法结构
DELIMITER $$ CREATE FUNCTION function_name([parameter ,...]) RETURNS return_datatype BEGIN -- 声明变量 DECLARE variable_name datatype [DEFAULT value]; -- 函数体 - SQL语句 -- 返回值 RETURN value; END $$ DELIMITER ;
创建一个存储函数时,MySQL 要求你明确声明该函数的特性之一 ==如果开了binlog==:
-
DETERMINISTIC
:函数对于相同的输入总是返回相同的结果。 -
NO SQL
:函数不包含任何 SQL 语句。 -
READS SQL DATA
:函数只读取数据,但不修改数据。 -
MODIFIES SQL DATA
:函数会修改数据。
计算相差天数
DELIMITER $$ CREATE FUNCTION calculate_age(birth_date DATE) RETURNS INT DETERMINISTIC BEGIN RETURN datediff(CURDATE(), birth_date); END $$ DELIMITER ;
根据学生ID获取性别
DELIMITER $$ CREATE FUNCTION get_gender_desc(student_id INT) RETURNS VARCHAR(10) READS SQL DATA BEGIN DECLARE gender CHAR(1); -- 获取学生性别 SELECT ssex INTO gender FROM t_student WHERE sid = student_id; -- 返回性别描述 IF gender = '男' THEN RETURN '男性'; ELSEIF gender = '女' THEN RETURN '女性'; ELSE RETURN '未知'; END IF; END $$ DELIMITER ;
-- 查询单个学生性别 SELECT sid, sname, get_gender_desc(sid) AS 性别 FROM t_student WHERE sid = 1001; -- 在完整查询中使用 SELECT sid, sname, sage, get_gender_desc(sid) AS 性别 FROM t_student ORDER BY sid;
判断成绩是否及格
DELIMITER $$ CREATE FUNCTION is_pass(score DECIMAL(5, 2)) RETURNS VARCHAR(10) deterministic BEGIN IF score >= 60 THEN RETURN '及格'; ELSE RETURN '不及格'; END IF; END $$ DELIMITER ;
-- 查看所有成绩是否及格 SELECT sid, cid, score, is_pass(score) AS 是否及格 FROM t_score; -- 结合WHERE条件使用 SELECT s.sid, st.sname, s.cid, c.cname, s.score, is_pass(s.score) AS 是否及格 FROM t_score s JOIN t_student st ON s.sid = st.sid JOIN t_course c ON s.cid = c.cid WHERE is_pass(s.score) = '不及格';
计算学生年龄
DELIMITER $$ CREATE FUNCTION calculate_student_age(student_id INT) RETURNS INT READS SQL DATA BEGIN DECLARE birth_date DATE; -- 获取学生出生日期 SELECT sage INTO birth_date FROM t_student WHERE sid = student_id; -- 计算年龄 RETURN TIMESTAMPDIFF(YEAR, birth_date, CURDATE()); END $$ DELIMITER ;
-- 查询所有学生的年龄 SELECT sid, sname, sage AS 出生日期, calculate_student_age(sid) AS 年龄 FROM t_student ORDER BY 年龄 DESC;
获取教师姓名
DELIMITER $$ CREATE FUNCTION get_teacher_name(teacher_id INT) RETURNS VARCHAR(50) READS SQL DATA BEGIN DECLARE teacher_name VARCHAR(50); SELECT tname INTO teacher_name FROM t_teacher WHERE tid = teacher_id; RETURN IFNULL(teacher_name, '未知教师'); END $$ DELIMITER ;
-- 查询课程对应的教师 SELECT cid, cname, tid AS 教师ID, get_teacher_name(tid) AS 教师姓名 FROM t_course;
计算学生的平均成绩
DELIMITER $$ CREATE FUNCTION get_student_avg_score(student_id INT) RETURNS DECIMAL(5, 2) READS SQL DATA BEGIN DECLARE avg_score DECIMAL(5, 2); SELECT AVG(score) INTO avg_score FROM t_score WHERE sid = student_id; RETURN IFNULL(avg_score, 0); END $$ DELIMITER ;
-- 查询指定学生的平均分 SELECT sid, sname, get_student_avg_score(sid) AS 平均分 FROM t_student WHERE sid = 1001; -- 按平均分对所有学生进行排名 SELECT sid, sname, get_student_avg_score(sid) AS 平均分 FROM t_student ORDER BY 平均分 DESC;
统计学生选修的课程数量
DELIMITER $$ CREATE FUNCTION count_student_courses(student_id INT) RETURNS INT READS SQL DATA BEGIN DECLARE course_count INT; SELECT COUNT(*) INTO course_count FROM t_score WHERE sid = student_id;
-- 查询所有学生选修的课程数量 SELECT sid, sname, count_student_courses(sid) AS 选修课程数 FROM t_student ORDER BY 选修课程数 DESC; -- 筛选选修课程数大于2的学生 SELECT sid, sname, count_student_courses(sid) AS 选修课程数 FROM t_student WHERE count_student_courses(sid) > 2;
获取课程的最高分
DELIMITER $$ CREATE FUNCTION get_course_max_score(course_id INT) RETURNS DECIMAL(5, 2) READS SQL DATA BEGIN DECLARE max_score DECIMAL(5, 2); SELECT MAX(score) INTO max_score FROM t_score WHERE cid = course_id; RETURN IFNULL(max_score, 0); END $$ DELIMITER ;
-- 查询所有课程的最高分 SELECT c.cid, c.cname, get_course_max_score(c.cid) AS 最高分 FROM t_course c ORDER BY 最高分 DESC;
学生成绩等级评定函数
DELIMITER $$ CREATE FUNCTION get_score_grade(score DECIMAL(5, 2)) RETURNS CHAR(1) DETERMINISTIC BEGIN DECLARE grade CHAR(1); CASE WHEN score >= 90 THEN SET grade = 'A'; WHEN score >= 80 THEN SET grade = 'B'; WHEN score >= 70 THEN SET grade = 'C'; WHEN score >= 60 THEN SET grade = 'D'; ELSE SET grade = 'F'; END CASE; RETURN grade; END $$ DELIMITER ;
-- 为所有成绩评定等级 SELECT s.sid, st.sname, c.cname, s.score, get_score_grade(s.score) AS 等级 FROM t_score s JOIN t_student st ON s.sid = st.sid JOIN t_course c ON s.cid = c.cid ORDER BY s.sid, s.cid; -- 统计各等级人数 SELECT get_score_grade(score) AS 等级, COUNT(*) AS 人数 FROM t_score GROUP BY 等级 ORDER BY 等级;
检查学生是否通过所有考试
DELIMITER $$ CREATE FUNCTION has_failed_courses(student_id INT) RETURNS VARCHAR(10) READS SQL DATA BEGIN DECLARE fail_count INT; SELECT COUNT(*) INTO fail_count FROM t_score WHERE sid = student_id AND score < 60; IF fail_count > 0 THEN RETURN '有不及格'; ELSE RETURN '全部及格'; END IF; END $$ DELIMITER ;
-- 查询所有学生的及格情况 SELECT s.sid, s.sname, has_failed_courses(s.sid) AS 及格情况 FROM t_student s ORDER BY s.sid; -- 筛选出有不及格科目的学生 SELECT s.sid, s.sname, has_failed_courses(s.sid) AS 及格情况 FROM t_student s WHERE has_failed_courses(s.sid) = '有不及格';
函数管理
查看函数
-- 查看当前数据库中所有函数 SHOW FUNCTION STATUS WHERE Db = DATABASE(); -- 查看特定函数的创建语句 SHOW CREATE FUNCTION function_name;
删除函数
DROP FUNCTION IF EXISTS function_name;
函数的局限性
-
无法执行事务:
-
函数内不能包含事务控制语句(START TRANSACTION, COMMIT, ROLLBACK)
-
复杂的事务处理应使用存储过程
-
-
不建议在函数中修改数据:
-
MySQL允许在函数中修改数据,但不推荐这样做
-
修改数据的操作应放在存储过程中
-
-
不能返回结果集:
-
函数只能返回单一值,不能返回多行结果
-
需要返回结果集的操作应使用存储过程
-