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

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 存储函数的概念、与存储…...

代码随想录_栈与队列

栈与队列 232.用栈实现队列 232. 用栈实现队列 使用栈实现队列的下列操作: push(x) – 将一个元素放入队列的尾部。 pop() – 从队列首部移除元素。 peek() – 返回队列首部的元素。 empty() – 返回队列是否为空。 思路: 定义两个栈: 入队栈, 出队栈, 控制出入…...

【微服务与分布式实践】探索 Sentinel

参数设置 熔断时长 、最小请求数、最大RT ms、比例阈值、异常数 熔断策略 慢调⽤⽐例 当单位统计时⻓内请求数⽬⼤于设置的最⼩请求数⽬,并且慢调⽤的⽐例⼤于阈值,则接下来的熔断时⻓内请求会⾃动被熔断 异常⽐例 当单位统计时⻓内请求数⽬⼤于设置…...

深入研究异常处理机制

一、原理探究 C异常处理 本节内容针对 Linux 下的 C 异常处理机制,重点在于研究如何在异常处理流程中利用溢出漏洞,所以不对异常处理及 unwind 的过程做详细分析,只做简单介绍 异常机制中主要的三个关键字:throw 抛出异常&#x…...

【memgpt】letta 课程4:基于latta框架构建MemGpt代理并与之交互

Lab 3: Building Agents with memory 基于latta框架构建MemGpt代理并与之交互理解代理状态,例如作为系统提示符、工具和agent的内存查看和编辑代理存档内存MemGPT 代理是有状态的 agents的设计思路 每个步骤都要定义代理行为 Letta agents persist information over time and…...

讯飞智作 AI 配音技术浅析(二):深度学习与神经网络

讯飞智作 AI 配音技术依赖于深度学习与神经网络,特别是 Tacotron、WaveNet 和 Transformer-TTS 模型。这些模型通过复杂的神经网络架构和数学公式,实现了从文本到自然语音的高效转换。 一、Tacotron 模型 Tacotron 是一种端到端的语音合成模型&#xff…...

基于单片机的超声波液位检测系统(论文+源码)

1总体设计 本课题为基于单片机的超声波液位检测系统的设计,系统的结构框图如图2.1所示。其中包括了按键模块,温度检测模块,超声波液位检测模块,显示模块,蜂鸣器等器件设备。其中,采用STC89C52单片机作为主控…...

Autogen_core: test_code_executor.py

目录 代码代码解释 代码 import textwrapimport pytest from autogen_core.code_executor import (Alias,FunctionWithRequirements,FunctionWithRequirementsStr,ImportFromModule, ) from autogen_core.code_executor._func_with_reqs import build_python_functions_file f…...

从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架

目录 前言 环境介绍 代码与动机 架构设计,优缺点 博客系列指引 前言 笔者前段时间花费了一周,整理了一下自从TM1637开始打算的,使用OLED来搭建一个通用的显示库的一个工程。笔者的OLED库已经开源到Github上了,地址在&#xf…...

Java实现.env文件读取敏感数据

文章目录 1.common-env-starter模块1.目录结构2.DotenvEnvironmentPostProcessor.java 在${xxx}解析之前执行,提前读取配置3.EnvProperties.java 这里的path只是为了代码提示4.EnvAutoConfiguration.java Env模块自动配置类5.spring.factories 自动配置和注册Enviro…...

Go反射指南

概念: 官方对此有个非常简明的介绍,两句话耐人寻味: 反射提供一种让程序检查自身结构的能力反射是困惑的源泉 第1条,再精确点的描述是“反射是一种检查interface变量的底层类型和值的机制”。 第2条,很有喜感的自嘲…...

Fullcalendar @fullcalendar/react 样式错乱丢失问题和导致页面卡顿崩溃问题

问题描述: 我使用 fullcalendar的react版本时,出现了一个诡异的问题,当我切换到 一个iframe页面时(整个页面是一个iframe嵌入的),再切换回来日历的样式丢失了!不仅丢失了样式还导致页面崩溃了&…...

【电工基础】4.低压电器元件,漏电保护器,熔断器,中间继电器

一。漏电保护器 1.使用区域 我们在家用总开关上使用空气开关(断路器),其余的厨房卧室为漏电保护器。 2.漏电保护器的简介 1.漏电:就是流入的电流和流出的电流不等,意味着电路回路中还有其它分支,可能是电流通过人体进…...

有限元分析学习——Anasys Workbanch第一阶段笔记梳理

第一阶段笔记主要源自于哔哩哔哩《ANSYS-workbench 有限元分析应用基础教程》 张晔 主要内容导图: 笔记导航如下: Anasys Workbanch第一阶段笔记(1)基本信息与结果解读_有限元分析变形比例-CSDN博客 Anasys Workbanch第一阶段笔记(2)网格单元与应力奇…...

C++中常用的十大排序方法之1——冒泡排序

成长路上不孤单😊😊😊😊😊😊 【😊///计算机爱好者😊///持续分享所学😊///如有需要欢迎收藏转发///😊】 今日分享关于C中常用的排序方法之——冒泡排序的相关…...

vscode+WSL2(ubuntu22.04)+pytorch+conda+cuda+cudnn安装系列

最近在家过年闲的没事,于是研究起深度学习开发工具链的配置和安装,之前欲与天公试比高,尝试在win上用vscodecuda11.6vs2019的cl编译器搭建cuda c编程环境,最后惨败,沦为笑柄,痛定思痛,这次直接和…...

手撕Diffusion系列 - 第十一期 - lora微调 - 基于Stable Diffusion(代码)

手撕Diffusion系列 - 第十一期 - lora微调 - 基于Stable Diffusion(代码) 目录 手撕Diffusion系列 - 第十一期 - lora微调 - 基于Stable Diffusion(代码)Stable Diffusion 原理图Stable Diffusion的原理解释Stable Diffusion 和Di…...

【Block总结】OutlookAttention注意力,捕捉细节和局部特征|即插即用

论文信息 标题: VOLO: Vision Outlooker for Visual Recognition作者: Li Yuan, Qibin Hou, Zihang Jiang, Jiashi Feng, Shuicheng Yan代码链接: https://github.com/sail-sg/volo论文链接: https://arxiv.org/pdf/2106.13112 创新点 前景注意力机制: VOLO引入了一种称为“…...

网络攻防实战指北专栏讲解大纲与网络安全法

专栏 本专栏为网络攻防实战指北,大纲如下所示 进度:目前已更完准备篇、HTML基础 计划:所谓基础不牢,地动山摇。所以下一步将持续更新基础篇内容 讲解信息安全时,结合《中华人民共和国网络安全法》(以下简…...

【已解决】windows7虚拟机安装VMtools频繁报错

为了在虚拟机VMware中安装win7,题主先在网上下载了windows7 professional版本的镜像,在vmware中安装vmtools时报错,信息如下 (安装程序无法继续,本程序需要您将此虚拟机上安装的操作系统更新到SP1) 然后就…...

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络&#xf…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...

【Oracle】分区表

个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)

引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...

人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent

安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...