MySQL自定义函数

一: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==:

  1. DETERMINISTIC:函数对于相同的输入总是返回相同的结果。

  2. NO SQL:函数不包含任何 SQL 语句。

  3. READS SQL DATA:函数只读取数据,但不修改数据。

  4. 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):函数的局限性

  1. 无法执行事务:

    • 函数内不能包含事务控制语句(START TRANSACTION, COMMIT, ROLLBACK)

    • 复杂的事务处理应使用存储过程

  2. 不建议在函数中修改数据:

    • MySQL允许在函数中修改数据,但不推荐这样做

    • 修改数据的操作应放在存储过程中

  3. 不能返回结果集:

    • 函数只能返回单一值,不能返回多行结果

    • 需要返回结果集的操作应使用存储过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值