MySQL 存储函数:数据库的自定义函数
在数据库开发中,存储函数(Stored Function)是一种非常有用的工具。它允许我们创建自定义的函数,这些函数可以在 SQL 查询中像内置函数一样使用,用于实现特定的逻辑和计算。本文将深入探讨 MySQL 存储函数的概念、与存储过程的区别、语法、以及实际应用,帮助你更好地利用存储函数扩展 MySQL 的功能。
一、什么是存储函数?
存储函数是一组预编译的SQL语句,它们被保存在数据库中,并且可以通过调用该函数来执行这些语句。与存储过程不同的是,存储函数必须返回一个单一的结果值。这使得它们非常适合用于执行复杂的计算或查询,并将结果返回给调用者。与存储过程类似,存储函数也具有以下特点:
- 预编译: 存储函数在创建时会被编译成可执行代码,这使得存储函数的执行速度比普通的 SQL 语句更快。
- 存储在数据库服务器:存储函数代码存储在数据库服务器端,避免了客户端和服务器之间传输大量的 SQL 语句,减少了网络开销。
- 通过名称调用:存储函数可以通过名称来调用,方便代码的复用。
- 返回值: 存储函数必须返回一个值, 可以在 SQL 查询语句中使用。
- 模块化:存储函数可以实现代码的模块化,提高代码的可维护性。
- 权限控制: 可以通过数据库的权限机制来限制存储函数的访问权限。
二、存储函数与存储过程的区别
| 特性 | 存储过程 (Stored Procedure) | 存储函数 (Stored Function) |
|---|---|---|
| 主要目的 | 执行一系列 SQL 语句,完成特定操作 | 执行计算或数据处理,返回一个值 |
| 返回值 | 可以有多个输出参数或无返回值 | 必须返回一个值 |
| 调用方式 | 使用 CALL 语句 | 在 SQL 查询语句中使用,像内置函数一样 |
| 使用场景 | 适用于复杂业务逻辑、数据操作 | 适用于数据计算、格式化、验证等 |
| 事务 | 可以使用事务 | 通常不能使用事务 |
三、存储函数的语法结构
3.1 创建存储函数:CREATE FUNCTION
DELIMITER //CREATE FUNCTION 函数名 ([IN] 参数名 数据类型,[IN] 参数名 数据类型,...
)
RETURNS 返回值数据类型
[函数特性]
BEGIN-- SQL 语句-- 返回值RETURN 值;
END //DELIMITER ;
DELIMITER: 在 MySQL 中,默认的语句结束符号是分号(;)。当你在存储过程或触发器中编写包含多个语句的代码时,MySQL 会将每个分号视为一个语句的结束,这会导致语法错误,因为存储过程或触发器需要包含多个语句。为了解决这个问题,可以使用DELIMITER命令来更改语句的结束符号。上述使用DELIMITER //命令将语句结束符号更改为双斜线(//),在END结尾加上双斜线(//)标志着函数结尾,然后使用DELIMITER ;将结束符号改回分号(;),完成命令。CREATE FUNCTION: 创建存储函数的关键字。 函数名: 存储函数的名称。IN: 输入参数,存储函数需要从外部接收的参数(存储函数只支持 IN 参数, 不支持 OUT 和 INOUT 参数)。RETURNS返回值数据类型: 指定存储函数返回值的类型。函数特性: 存储函数的特性,分为如下几类。DETERMINISTIC: 表示函数每次输入相同的参数都会返回相同的结果。NOT DETERMINISTIC: 表示函数每次输入相同的参数,可能会返回不同的结果,例如其中使用了NOW()。NO SQL: 表示存储函数不读取或修改数据库中的任何数据。READS SQL DATA: 表示存储函数读取数据库中的数据,但不修改数据。MODIFIES SQL DATA: 表示存储函数会修改数据库中的数据。SQL SECURITY DEFINER: 表示使用存储函数创建者的权限执行。SQL SECURITY INVOKER: 表示存储函数以调用者 (调用存储函数的用户) 的权限执行 。COMMENT 'string': 用于为存储函数添加注释,方便文档记录。LANGUAGE SQL(可选): 用于声明存储函数使用 SQL 语言编写。
BEGIN ... END: 定义存储函数的起始和结束。RETURN值: 指定函数的返回值。
3.2 调用存储函数:
SELECT 函数名(参数1, 参数2, ...);
3.3 删除存储函数:DROP FUNCTION
DROP FUNCTION IF EXISTS 函数名;
3.4 变量声明与赋值
DECLARE v_count INT DEFAULT 0;SET v_count = (SELECT COUNT(*) FROM employees WHERE salary > 5000);
3.5 条件判断
IF 条件 THEN-- SQL 语句
ELSEIF 条件 THEN-- SQL 语句
ELSE-- SQL 语句
END IF;
3.6 条件判断
WHILE 条件 DO-- SQL 语句END WHILE;
3.7 错误处理
DECLARE CONTINUE HANDLER FOR NOT FOUND
BEGIN-- Error handling codeRETURN 0; -- Return a default value in case of an error
END;
四、存储函数的示例
计算员工奖金:假设我们需要根据员工的工作年限和绩效评分来计算他们的奖金。工作年限超过5年且绩效评分为优秀的员工将获得基本工资10%的奖金,如果没有就只能获得工资5%的奖金。我们可以编写一个存储函数来实现这一需求。
表结构
CREATE TABLE employees (emp_id INT PRIMARY KEY,name VARCHAR(100),hire_date DATE,performance_rating ENUM('Poor', 'Average', 'Good', 'Excellent'),base_salary DECIMAL(10,2),department_id INT
);
插入数据
INSERT INTO employees (emp_id, name, hire_date, performance_rating, base_salary, department_id) VALUES (1, 'Alice', '2015-06-01', 'Excellent', 8000.00, 1);
INSERT INTO employees (emp_id, name, hire_date, performance_rating, base_salary, department_id) VALUES (2, 'Bob', '2017-03-15', 'Good', 6500.00, 1);
INSERT INTO employees (emp_id, name, hire_date, performance_rating, base_salary, department_id) VALUES (3, 'Carol', '2019-09-22', 'Average', 5000.00, 2);
INSERT INTO employees (emp_id, name, hire_date, performance_rating, base_salary, department_id) VALUES (4, 'Dave', '2016-11-10', 'Poor', 4500.00, 2);
INSERT INTO employees (emp_id, name, hire_date, performance_rating, base_salary, department_id) VALUES (5, 'Eve', '2018-07-30', 'Good', 7000.00, 3);
INSERT INTO employees (emp_id, name, hire_date, performance_rating, base_salary, department_id) VALUES (6, 'Frank', '2020-01-15', 'Excellent', 9000.00, 3);
INSERT INTO employees (emp_id, name, hire_date, performance_rating, base_salary, department_id) VALUES (7, 'Grace', '2014-05-05', 'Excellent', 10000.00, 4);
INSERT INTO employees (emp_id, name, hire_date, performance_rating, base_salary, department_id) VALUES (8, 'Heidi', '2019-12-01', 'Average', 5500.00, 4);
存储函数实现
CREATE FUNCTION CalculateBonus(p_emp_id INT)
RETURNS DECIMAL(10,2)
READS SQL DATA
BEGINDECLARE v_years_of_service INT;DECLARE v_performance_rating ENUM('Poor', 'Average', 'Good', 'Excellent');DECLARE v_bonus DECIMAL(10,2);-- 获取指定员工的服务年限和绩效评分SELECT TIMESTAMPDIFF(YEAR, hire_date, CURDATE()), performance_rating INTO v_years_of_service, v_performance_ratingFROM employeesWHERE emp_id = p_emp_id;-- 根据条件计算奖金IF v_years_of_service > 5 AND v_performance_rating = 'Excellent' THENSELECT base_salary * 0.1 INTO v_bonus FROM employees WHERE emp_id = p_emp_id;ELSESELECT base_salary * 0.05 INTO v_bonus FROM employees WHERE emp_id = p_emp_id;END IF;RETURN v_bonus;
END
五、最佳实践
- 谨慎使用存储函数:存储函数适用于简单的计算和数据处理,避免在存储函数中执行复杂的查询操作。避免使用存储函数处理事务,存储函数不能进行事务控制。
- 保持存储函数简洁:存储函数应该只完成特定的功能,避免过于复杂。存储函数的逻辑应该尽量简单清晰,便于理解和维护。
- 使用
DETERMINISTIC:如果存储函数的输出只依赖于输入参数,则应该使用DETERMINISTIC特性,这样可以提高 MySQL 查询优化器的性能。如果存储函数的输出不只依赖于输入参数, 例如使用NOW()等函数,则不应该使用DETERMINISTIC特性。 - 良好的代码风格:使用有意义的函数名和变量名。使用缩进和注释,保持代码可读性。
- 权限控制:应该控制存储函数的访问权限,只允许有权限的用户访问。
- 避免副作用:存储函数应该避免产生副作用,例如修改数据库表中的数据,应该使用存储过程来完成此类操作。
相关文章:
MySQL 存储函数:数据库的自定义函数
在数据库开发中,存储函数(Stored Function)是一种非常有用的工具。它允许我们创建自定义的函数,这些函数可以在 SQL 查询中像内置函数一样使用,用于实现特定的逻辑和计算。本文将深入探讨 MySQL 存储函数的概念、与存储…...
【Rust自学】15.6. RefCell与内部可变性:“摆脱”安全性限制
题外话,这篇文章一共4050字,是截止到目前为止最长的文章,如果你能坚持读完并理解,那真的很强! 喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以…...
Luzmo 专为SaaS公司设计的嵌入式数据分析平台
Luzmo 是一款嵌入式数据分析平台,专为 SaaS 公司设计,旨在通过直观的可视化和快速开发流程简化数据驱动决策。以下是关于 Luzmo 的详细介绍: 1. 背景与定位 Luzmo 前身为 Cumul.io ,专注于为 SaaS 公司提供嵌入式分析解决方案。…...
数组at()方法:负索引的救赎与JavaScript标准化之路
数组at()方法:负索引的救赎与JavaScript标准化之路 从一次代码评审说起 在某次团队代码评审中,小白注意到有同事写下了这样的代码: const lastItem arr[arr.length - 1];这让我回想起自己早期开发时被负索引问题困扰的经历。今天…...
HTML<label>标签
例子 三个带标签的单选按钮: <form action"/action_page.php"> <input type"radio" id"html" name"fav_language" value"HTML"> <label for"html">HTML</label><br&…...
约瑟夫问题(信息学奥赛一本通-2037)
【题目描述】 N个人围成一圈,从第一个人开始报数,数到M的人出圈;再由下一个人开始报数,数到M 的人出圈;…输出依次出圈的人的编号。 【输入】 输入N和M。 【输出】 输出一行,依次出圈的人的编号。 【输入样…...
二分查找题目:寻找两个正序数组的中位数
文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题:寻找两个正序数组的中位数 出处:4. 寻找两个正序数组的中位数 难度 8 级 题目描述 要求 给定两个大…...
【技术洞察】2024科技绘卷:浪潮、突破、未来
涌动与突破 2024年,科技的浪潮汹涌澎湃,人工智能、量子计算、脑机接口等前沿技术如同璀璨星辰,方便了大家的日常生活,也照亮了人类未来的道路。这一年,科技的突破与创新不断刷新着人们对未来的想象。那么回顾2024年的科…...
【Linux】gdb——Linux调试器
gdb使用背景 程序的发布方式有两种,debug模式和release模式 Linux gcc/g出来的二进制程序,默认是release模式 要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g 选项 gdb使用方法 首先进入gdb gdb test_glist显示代码 断点 b 行…...
fpga系列 HDL:XILINX Vivado Vitis 高层次综合(HLS) 实现 EBAZ板LED控制(上)
目录 创建工程创建源文件并编写C代码C仿真综合仿真导出RTL CG导出RTL错误处理: 创建工程 创建源文件并编写C代码 创建源文件(Souces下的hlsv.h和hlsv.cpp,Test Bench下的test_hlsv1.cpp): hlsv1.h #ifndef HLSV1 #define HLSV1 #include &l…...
卡特兰数学习
1,概念 卡特兰数(英语:Catalan number),又称卡塔兰数,明安图数。是组合数学中一种常出现于各种计数问题中的数列。它在不同的计数问题中频繁出现。 2,公式 卡特兰数的递推公式为:f(…...
度小满Java开发面试题及参考答案 (上)
String 是基本类型吗?String、StringBuffer、StringBuilder 的区别是什么?拼接字符串有哪些做法? String 不是基本类型,它是 Java 中的一个类,属于引用类型。 下面来看看 String、StringBuffer、StringBuilder 的区别: 类型可变性线程安全性性能适用场景String不可变线程…...
Python-基于PyQt5,json和playsound的通用闹钟
前言:刚刚结束2024年秋季学期的学习,接下来我们继续来学习PyQt5。由于之前我们已经学习了PyQt5以及PyUIC,Pyrcc和QtDesigner的安装,配置。所以接下来我们一起深入PyQt5,学习如何利用PyQt5进行实际开发-基于PyQt5,json和…...
关于数字地DGND和模拟地AGND隔离
文章目录 前言一、1、为什么要进行数字地和模拟地隔离二、隔离元件1.①0Ω电阻:2.②磁珠:3.电容:4.④电感: 三、隔离方法①单点接地②数字地与模拟地分开布线,最后再PCB板上一点接到电源。③电源隔离④、其他隔离方法 …...
小识Java死锁是否会造成CPU100%?
死锁或者大量的死锁不一定会直接导致CPU占用率达到100%。以下是详细分析: 一、死锁对CPU的影响 资源占用:死锁是指两个或多个线程(或进程)在相互等待对方释放资源,导致所有涉及的线程都无法继续执行。在死锁状态下&a…...
DeepSeek R1学习
0.回顾: https://blog.csdn.net/Together_CZ/article/details/144431432?ops_request_misc%257B%2522request%255Fid%2522%253A%25226574a586f0850d0329fbb720e5b8d5a9%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id…...
激光线扫相机无2D图像的标定方案
方案一:基于运动控制平台的标定 适用场景:若激光线扫相机安装在可控运动平台(如机械臂、平移台、旋转台)上,且平台的运动精度已知(例如通过编码器或高精度步进电机控制)。 步骤: 标…...
12 款开源OCR发 PDF 识别框架
2024 年 12 款开源文档解析框架的选型对比评测:PDF解析、OCR识别功能解读、应用场景分析及优缺点比较 这是该系列的第二篇文章,聚焦于智能文档处理(特别是 PDF 解析)。无论是在模型预训练的数据收集阶段,还是基于 RAG…...
【反悔堆】【hard】力扣871. 最低加油次数
汽车从起点出发驶向目的地,该目的地位于出发位置东面 target 英里处。 沿途有加油站,用数组 stations 表示。其中 stations[i] [positioni, fueli] 表示第 i 个加油站位于出发位置东面 positioni 英里处,并且有 fueli 升汽油。 假设汽车油…...
为什么应用程序是特定于操作系统的?[计算机原理]
你把WINDOWS程序复制到MAC上使用,会发现无法运行。你可能会说,MAC是arm处理器,而WINDWOS是X86 处理器。但是在2019年,那时候MAC电脑还全是Intel处理器,在同样的X86芯片上,运行MAC和WINDOWS 程序还是无法互相…...
多项日常使用测试,带你了解如何选择AI工具 Deepseek VS ChatGpt VS Claude
多项日常使用测试,带你了解如何选择AI工具 Deepseek VS ChatGpt VS Claude 注:因为考虑到绝大部分人的使用,我这里所用的模型均为免费模型。官方可访问的。ChatGPT这里用的是4o Ai对话,编程一直以来都是人们所讨论的话题。Ai的出现…...
什么是循环神经网络?
一、概念 循环神经网络(Recurrent Neural Network, RNN)是一类用于处理序列数据的神经网络。与传统的前馈神经网络不同,RNN具有循环连接,可以利用序列数据的时间依赖性。正因如此,RNN在自然语言处理、时间序列预测、语…...
Flink运行时架构
一、系统架构 1)作业管理器(JobManager) JobManager是一个Flink集群中任务管理和调度的核心,是控制应用执行的主进程。也就是说,每个应用都应该被唯一的JobManager所控制执行。 JobManger又包含3个不同的组件。 &am…...
网络工程师 (6)操作系统概述
一、操作系统的定义 (一)基本定义 操作系统(Operating System,简称OS)是计算机系统中至关重要的基础性系统软件。它是计算机硬件与上层软件之间的桥梁,负责管理和控制整个计算机系统的硬件和软件资源&…...
【2025年数学建模美赛C题】第1-5问F奖解题思路+高级绘图+可运行代码
基于多模型分析的奥运会奖牌预测与影响因素研究 解题思路一、问题重述二、问题分析三、模型假设与符号说明四、数据预处理五、奖牌榜预测5.1 基于LSTM长短期记忆循环神经网络的预测模型的建立5.2 模型预测结果 六、首枚奖牌预测6.1 BP神经网络的建立6.2 模型预测结果 七、各国奖…...
StarRocks 安装部署
StarRocks 安装部署 StarRocks端口: 官方《配置检查》有服务端口详细描述: https://docs.starrocks.io/zh/docs/deployment/environment_configurations/ StarRocks架构:https://docs.starrocks.io/zh/docs/introduction/Architecture/ Sta…...
RoboMaster- RDK X5能量机关实现案例(一)识别
作者:SkyXZ CSDN:https://blog.csdn.net/xiongqi123123 博客园:https://www.cnblogs.com/SkyXZ 在RoboMaster的25赛季,我主要负责了能量机关的视觉方案开发,目前整体算法已经搭建完成,实际方案上我使用的上…...
llama.cpp LLM_ARCH_DEEPSEEK and LLM_ARCH_DEEPSEEK2
llama.cpp LLM_ARCH_DEEPSEEK and LLM_ARCH_DEEPSEEK2 1. LLM_ARCH_DEEPSEEK and LLM_ARCH_DEEPSEEK22. LLM_ARCH_DEEPSEEK and LLM_ARCH_DEEPSEEK23. struct ggml_cgraph * build_deepseek() and struct ggml_cgraph * build_deepseek2()References 不宜吹捧中国大语言模型的同…...
检测到联想鼠标自动调出运行窗口,鼠标自己作为键盘操作
联想鼠标会自动时不时的调用“运行”窗口 然后鼠标自己作为键盘输入 然后打开这个网页 (不是点击了什么鼠标外加按键,这个鼠标除了左右和中间滚轮,没有其他按键了)...
-bash: ./uninstall.command: /bin/sh^M: 坏的解释器: 没有那个文件或目录
终端报错: -bash: ./uninstall.command: /bin/sh^M: 坏的解释器: 没有那个文件或目录原因:由于文件行尾符不匹配导致的。当脚本文件在Windows环境中创建或编辑后,行尾符为CRLF(即回车和换行,\r\n)…...
