一:MySQL函数介绍
MySQL自定义函数(Function)是一组预编译的SQL语句集合,它们被存储在数据库中并可重复使用。函数接受输入参数,执行特定操作,并且必须返回一个单一值。
函数的基本特点
- 封装性:将多个SQL操作封装为一个单元
- 重用性:能在多个SQL语句中重复调用
- 简化操作:使复杂的操作变得简单
- 返回单一值:必须且只能返回一个值
- 可在SQL表达式中使用:可以直接在SELECT语句中使用
二:函数与存储过程的区别
函数和存储过程都是MySQL中的程序化对象,但它们在用途、语法和行为上有明显区别。
需要获取学生的平均分数:
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) = '有不及格';
四:函数管理
(1):查看函数
-- 查看当前数据库中所有函数
SHOW FUNCTION STATUS WHERE Db = DATABASE();
-- 查看特定函数的创建语句
SHOW CREATE FUNCTION function_name;
(2):删除函数
DROP FUNCTION IF EXISTS function_name;
(3):函数的局限性
-
无法执行事务:
-
函数内不能包含事务控制语句(START TRANSACTION, COMMIT, ROLLBACK)
-
复杂的事务处理应使用存储过程
-
-
不建议在函数中修改数据:
-
MySQL允许在函数中修改数据,但不推荐这样做
-
修改数据的操作应放在存储过程中
-
-
不能返回结果集:
-
函数只能返回单一值,不能返回多行结果
-
需要返回结果集的操作应使用存储过程
-