mysql 存储过程和自定义函数 详解

news2025/2/11 0:13:08

首先创建存储过程或者自定义函数时,都要使用use database 切换到目标数据库,因为存储过程和自定义函数都是属于某个数据库的。

存储过程是一种预编译的 SQL 代码集合,封装在数据库对象中。以下是一些常见的存储过程的关键字:

存储过程

1. 存储过程的定义

  • CREATE PROCEDURE: 用于创建一个新的存储过程。

    CREATE PROCEDURE procedure_name (parameter_list)
    BEGIN
        -- 存储过程体
    END;
  • DROP PROCEDURE: 用于删除已存在的存储过程。

    DROP PROCEDURE procedure_name;

2. 参数定义

  • IN: 表示输入参数。

  • OUT: 表示输出参数。

  • INOUT: 表示既可以输入又可以输出的参数。

    CREATE PROCEDURE my_procedure(IN param1 INT, OUT param2 INT)
    BEGIN
        -- 存储过程体
    END;

3. 变量声明与操作

  • DECLARE: 定义局部变量、条件和游标。

    DECLARE var1 INT DEFAULT 0;
    DECLARE var2 VARCHAR(50);
  • SET: 用于给变量赋值。

    SET var1 = 10;

4. 控制流程

  • BEGIN/END: 标记存储过程块的开始和结束。

    BEGIN
        -- 存储过程体
    END;
  • IF 条件判断

    IF 语句用于简单的条件分支。

    语法格式
    IF condition THEN
        SQL逻辑
    ELSEIF condition THEN
        SQL逻辑
    ELSE
        SQL逻辑
    END IF;
    案例

    根据用户 ID 返回不同的信息。

    DELIMITER //
    CREATE PROCEDURE CheckUser(IN userId VARCHAR(32))
    BEGIN
        DECLARE userName VARCHAR(32);
        IF userId = 'APP-2016-00494878' THEN
            SELECT username INTO userName FROM users WHERE userid = userId;
            SELECT userName;
        ELSEIF userId = 'APP-2016-7777777' THEN
            SELECT userage INTO userName FROM users WHERE userid = userId;
            SELECT userName;
        ELSE
            SELECT userId;
        END IF;
    END //
    DELIMITER ;

    调用存储过程:

    CALL CheckUser('APP-2016-00494878');
  • CASE: 用于多条件判断。

  • 语法格式
    CASE
        WHEN condition1 THEN
            SQL逻辑
        WHEN condition2 THEN
            SQL逻辑
        ELSE
            SQL逻辑
    END CASE;
  • 根据用户角色返回不同的权限级别。

  • DELIMITER //
    CREATE PROCEDURE GetUserRole(IN userId INT)
    BEGIN
        DECLARE userRole VARCHAR(20);
        SELECT role INTO userRole FROM users WHERE id = userId;
        CASE userRole
            WHEN 'admin' THEN
                SELECT 'Administrator';
            WHEN 'user' THEN
                SELECT 'Standard User';
            ELSE
                SELECT 'Guest';
        END CASE;
    END //
    DELIMITER ;

    调用存储过程:

    CALL GetUserRole(1);
  • LOOP/WHILE/REPEAT: 实现循环操作。

    LOOP_LABEL: LOOP
        -- 循环体
        IF condition THEN
            LEAVE LOOP_LABEL;
        END IF;
    END LOOP;

 WHILE 循环

WHILE 循环在条件为真时执行循环体中的 SQL 语句。

语法格式
WHILE 条件 DO
    SQL逻辑
END WHILE;
案例

计算从 1 累加到 n 的值,n 为传入的参数值。

DELIMITER //
CREATE PROCEDURE CalculateSum(IN n INT)
BEGIN
    DECLARE total INT DEFAULT 0;
    WHILE n > 0 DO
        SET total = total + n;
        SET n = n - 1;
    END WHILE;
    SELECT total;
END //
DELIMITER ;

调用存储过程:

CALL CalculateSum(100);

 

REPEAT 循环

REPEAT 循环至少执行一次循环体中的 SQL 语句,直到条件为真时退出循环。

语法格式
REPEAT
    SQL逻辑
UNTIL 条件
END REPEAT;
案例

计算从 1 累加到 n 的值,n 为传入的参数值。

DELIMITER //
CREATE PROCEDURE CalculateSumRepeat(IN n INT)
BEGIN
    DECLARE total INT DEFAULT 0;
    REPEAT
        SET total = total + n;
        SET n = n - 1;
    UNTIL n <= 0
    END REPEAT;
    SELECT total;
END //
DELIMITER ;

调用存储过程:

CALL CalculateSumRepeat(100);

LOOP 循环

LOOP 循环是无条件循环,通常与 LEAVE 语句结合使用来退出循环。

语法格式
[loop_label:] LOOP
    SQL逻辑
END LOOP [loop_label];
案例

计算从 1 累加到 n 的值,n 为传入的参数值。

DELIMITER //
CREATE PROCEDURE CalculateSumLoop(IN n INT)
BEGIN
    DECLARE total INT DEFAULT 0;
    sum_loop: LOOP
        IF n <= 0 THEN
            LEAVE sum_loop;
        END IF;
        SET total = total + n;
        SET n = n - 1;
    END LOOP sum_loop;
    SELECT total;
END //
DELIMITER ;

调用存储过程:

CALL CalculateSumLoop(100);

 

5. 条件处理

  • DECLARE HANDLER: 定义异常处理程序。

    DECLARE CONTINUE HANDLER FOR SQL_ERROR_CODE error_code
    BEGIN
        -- 异常处理语句
    END;

6. 游标操作

  • DECLARE CURSOR: 声明游标。

    DECLARE cursor_name CURSOR FOR SELECT column1, column2 FROM table WHERE condition;
  • OPEN CURSOR: 打开游标。

    OPEN cursor_name;
  • FETCH CURSOR: 读取游标数据。

    FETCH cursor_name INTO var1, var2;
  • CLOSE CURSOR: 关闭游标。

    CLOSE cursor_name;

7. 调试与优化

  • SET: 调整优化器参数。

    SET optimizer_switch = 'index_merge=on';
  • SHOW VARIABLES: 查看系统变量。

    SHOW VARIABLES LIKE 'optimizer_switch';

8.案例 

以下是一个包含事务处理的存储过程示例:

DELIMITER //

CREATE PROCEDURE transfer_funds(IN from_account INT, IN to_account INT, IN amount DECIMAL(10,2))
BEGIN
    START TRANSACTION;

    IF amount > 0 THEN
        -- 从源账户扣除金额
        UPDATE accounts SET balance = balance - amount WHERE id = from_account;
        -- 向目标账户增加金额
        UPDATE accounts SET balance = balance + amount WHERE id = to_account;
        -- 提交事务
        COMMIT;
    ELSE
        -- 回滚事务
        ROLLBACK;
    END IF;
END //

DELIMITER ;

这个存储过程通过事务确保资金转账操作的原子性。

9.补充知识:游标

注意事项

  • 游标只能在存储过程和函数中使用

  • 游标是只读的,不能用于修改数据,但可以通过 SELECT 查询结果集。

  • 需要显式地打开和关闭游标,以确保资源的正确释放。

通过使用游标,可以对查询结果集进行逐行处理,这对于需要对每行数据执行复杂操作的场景非常有用

DELIMITER //
CREATE PROCEDURE ProcessOrders()
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE orderId INT;
    DECLARE orderStatus VARCHAR(20);

    -- 声明一个名为 cur 的游标。
    -- 该游标基于查询 SELECT id, status FROM orders,用于存储查询结果集。
    -- 可以通过游标逐行访问和操作 orders 表中的每一行数据。
    DECLARE cur CURSOR FOR SELECT id, status FROM orders;
    -- 定义一个异常处理程序,当游标遍历完所有行(触发 NOT FOUND 异常)时,将变量 done 设置为 1。
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    OPEN cur; -- 打开游标
    order_loop: LOOP
        FETCH cur INTO orderId, orderStatus; -- 从游标中提取数据
        IF done THEN
            LEAVE order_loop; -- 如果没有更多数据,退出循环
        END IF;
        -- 在这里处理每一行数据
        UPDATE orders SET status = 'processed' WHERE id = orderId;
    END LOOP order_loop;
    CLOSE cur; -- 关闭游标
END //
DELIMITER ;

在这个存储过程中,当游标遍历完所有行时,FETCH cur INTO orderId, orderStatus 会触发 NOT FOUND 异常。此时,CONTINUE HANDLERdone 设置为 1,退出循环。

通过这种方式,可以优雅地处理游标遍历完成的情况,确保程序不会因异常而中断。

10.查询当前数据库有哪些存储过程 

SELECT 
    SPECIFIC_NAME AS '存储过程名', 
    ROUTINE_SCHEMA AS '数据库名', 
    CREATED AS '创建时间', 
    LAST_ALTERED AS '最后修改时间'
FROM 
    information_schema.ROUTINES
WHERE 
    ROUTINE_TYPE = 'PROCEDURE'
    AND ROUTINE_SCHEMA = 'test_mybatis';

自定义函数

1. 定义自定义函数

  • CREATE FUNCTION: 用于创建一个新的自定义函数。

    CREATE FUNCTION function_name (parameter_list)
    RETURNS return_type
    BEGIN
        -- 函数体
    END;
    • function_name: 函数名称。

    • parameter_list: 参数列表,参数可以是 IN 类型。

    • RETURNS: 指定函数返回值的类型。

2. 参数定义

  • IN: 定义输入参数。MySQL 的自定义函数只支持 IN 类型的参数。

    CREATE FUNCTION add_numbers(IN a INT, IN b INT)
    RETURNS INT
    BEGIN
        RETURN a + b;
    END;

3. 函数体

  • BEGIN/END: 标记函数体的开始和结束。

    BEGIN
        -- 函数逻辑
    END;

4. 返回值

  • RETURN: 用于返回函数的计算结果。

    RETURN value;

5. 属性

  • DETERMINISTICNOT DETERMINISTIC: 标记函数是否是确定性的。

    • 确定性函数:对于相同的输入参数总是返回相同的结果。

    • 非确定性函数:对于相同的输入参数可能返回不同的结果。

    CREATE FUNCTION function_name (parameter_list)
    RETURNS return_type DETERMINISTIC
    BEGIN
        -- 函数逻辑
    END;

6. 修改或删除函数

  • ALTER FUNCTION: 修改已存在的自定义函数。

  • DROP FUNCTION: 删除已存在的自定义函数。

    DROP FUNCTION function_name;

7. 调用函数

  • 可以直接在 SQL 语句中调用自定义函数。

    SELECT add_numbers(5, 10);

存储过程和自定义函数区别 

特性存储过程自定义函数
定义是一组预编译的 SQL 语句和流程控制语句的集合,可以包含多个 SQL 语句和复杂逻辑。是一个用户定义的函数,用于封装特定的功能逻辑,返回一个值。
返回值可以没有返回值,也可以通过 OUT 参数返回多个值。必须返回一个值,返回值类型在创建函数时指定。
参数类型支持 INOUT 和 INOUT 类型的参数。只支持 IN 类型的参数。
调用方式使用 CALL 语句调用,不能在 SELECT 中直接调用。可以在 SQL 语句中直接调用,如 SELECTWHEREORDER BY 等。
事务处理可以包含事务操作,控制事务的提交和回滚。不支持事务操作。
代码重用适合封装复杂的业务逻辑,便于维护和代码重用。适合封装简单的逻辑,如计算、转换或条件判断,便于在多个地方重用。
性能存储过程在服务器端执行,与应用程序交互次数少,性能较高。自定义函数在查询中调用时,可能会导致性能问题,需要谨慎使用。
适用场景适用于执行复杂操作的场景,如批量更新数据、执行多个 SQL 语句或返回结果集。适用于需要返回单个值的场景,如计算、转换或简单的逻辑判断。

总结

  • 存储过程:适合执行复杂的操作,可以返回多个值或结果集,适用于批量更新数据、执行多个 SQL 语句或返回结果集等场景。

  • 自定义函数:适合返回单个值的简单逻辑,可以直接在 SQL 语句中调用,适用于计算、转换或条件判断等场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2296038.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloud - Nacos注册/配置中心

前言 该博客为Nacos学习笔记&#xff0c;主要目的是为了帮助后期快速复习使用 学习视频&#xff1a;7小快速通关SpringCloud 辅助文档&#xff1a;SpringCloud快速通关 源码地址&#xff1a;cloud-demo 一、简介 Nacos官网&#xff1a;https://nacos.io/docs/next/quickstar…

C++ 继承(1)

1.继承概念 我们平时有时候在写多个有内容重复的类的时候会很麻烦 比如我要写Student Teacher Staff 这三个类 里面都要包含 sex name age成员变量 唯一不同的可能有一个成员变量 但是这三个成员变量我要写三遍 太麻烦了 有没有好的方式呢&#xff1f; 有的 就是继承…

【C语言】传值调用与传址调用详解

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;传值调用1. 什么是传值调用&#xff1f;2. 示例代码&#xff1a;传值调用失败的情况执行结果&#xff1a; 3. 为什么传值调用无法修改外部变量&#xff1f; &#x1f4…

蓝桥杯C语言组:图论问题

蓝桥杯C语言组图论问题研究 摘要 图论是计算机科学中的一个重要分支&#xff0c;在蓝桥杯C语言组竞赛中&#xff0c;图论问题频繁出现&#xff0c;对参赛选手的算法设计和编程能力提出了较高要求。本文系统地介绍了图论的基本概念、常见算法及其在蓝桥杯C语言组中的应用&#…

windows通过网络向Ubuntu发送文件/目录

由于最近要使用树莓派进行一些代码练习&#xff0c;但是好多东西都在windows里或虚拟机上&#xff0c;就想将文件传输到树莓派上&#xff0c;但试了发现u盘不能简单传送&#xff0c;就在网络上找到了通过windows 的scp命令传送 前提是树莓派先开启ssh服务&#xff0c;且Window…

Unity抖音云启动测试:如何用cmd命令行启动exe

相关资料&#xff1a;弹幕云启动&#xff08;原“玩法云启动能力”&#xff09;_直播小玩法_抖音开放平台 1&#xff0c;操作方法 在做云启动的时候&#xff0c;接完发现需要命令行模拟云环境测试启动&#xff0c;所以研究了下。 首先进入cmd命令&#xff0c;CD进入对应包的文件…

ZU47DR 100G光纤 高性能板卡

简介 2347DR是一款最大可提供8路ADC接收和8路DAC发射通道的高性能板卡。板卡选用高性价比的Xilinx的Zynq UltraScale RFSoC系列中XCZU47DR-FFVE1156作为处理芯片&#xff08;管脚可以兼容XCZU48DR-FFVE1156&#xff0c;主要差别在有无FEC&#xff08;信道纠错编解码&#xff0…

【算法】动态规划专题⑥ —— 完全背包问题 python

目录 前置知识进入正题模板 前置知识 【算法】动态规划专题⑤ —— 0-1背包问题 滚动数组优化 完全背包问题是动态规划中的一种经典问题&#xff0c;它与0-1背包问题相似&#xff0c;但有一个关键的区别&#xff1a;在完全背包问题中&#xff0c;每种物品都有无限的数量可用。…

C#中深度解析BinaryFormatter序列化生成的二进制文件

C#中深度解析BinaryFormatter序列化生成的二进制文件 BinaryFormatter序列化时,对象必须有 可序列化特性[Serializable] 一.新建窗体测试程序BinaryDeepAnalysisDemo,将默认的Form1重命名为FormBinaryDeepAnalysis 二.新建测试类Test Test.cs源程序如下: using System; us…

51单片机之引脚图(详解)

8051单片机引脚分类与功能笔记 1. 电源引脚 VCC&#xff08;第40脚&#xff09;&#xff1a;接入5V电源&#xff0c;为单片机提供工作电压。GND&#xff08;第20脚&#xff09;&#xff1a;接地端&#xff0c;确保电路的电位参考点。 2.时钟引脚 XTAL1&#xff08;第19脚&a…

jupyterLab插件开发

jupyter lab安装、配置&#xff1a; jupyter lab安装、配置教程_容器里装jupyterlab-CSDN博客 『Linux笔记』服务器搭建神器JupyterLab_linux_布衣小张-腾讯云开发者社区 Jupyter Lab | 安装、配置、插件推荐、多用户使用教程-腾讯云开发者社区-腾讯云 jupyterLab插件开发教…

配置#include “nlohmann/json.hpp“,用于处理json文件

#include “nlohmann/json.hpp” // 需要安装 nlohmann/json.hpp 头文件 using json = nlohmann::json; 下载链接:https://github.com/nlohmann/json/tree/develop 1.下载并解压:首先,需要从nlohmann/json的GitHub仓库下载源代码,并解压得到的文件。 地址: nlohmann/json…

MATLAB | 基于Theil-Sen斜率和Mann-Kendall检验的栅格数据趋势分析

最近看到一些博主分享关于 SenMK 检验的代码&#xff0c;对于新手来说可能有点复杂。我们编写了一段 MATLAB 代码&#xff0c;能够一次性解决这些问题&#xff0c;简化操作流程。我们还准备了几个关于趋势检验的空间分布图&#xff0c;供大家参考。 一、Sens Slope和Mann-Kenda…

Windows 系统下使用 Ollama 离线部署 DeepSeek - R1 模型指南

引言 随着人工智能技术的飞速发展&#xff0c;各类大语言模型层出不穷。DeepSeek - R1 凭借其出色的语言理解和生成能力&#xff0c;受到了广泛关注。而 Ollama 作为一款便捷的模型管理和部署工具&#xff0c;能够帮助我们轻松地在本地环境中部署和使用模型。本文将详细介绍如…

Docker、Ollama、Dify 及 DeepSeek 安装配置与搭建企业级本地私有化知识库实践

在现代企业中&#xff0c;管理和快速访问知识库是提升工作效率、促进创新的关键。为了满足这些需求&#xff0c;企业越来越倾向于构建本地私有化的知识库系统&#xff0c;这样可以更好地保护企业数据的安全性和隐私性。本文将介绍如何利用 **Docker**、**Ollama**、**Dify** 和…

【漫话机器学习系列】087.常见的神经网络最优化算法(Common Optimizers Of Neural Nets)

常见的神经网络优化算法 1. 引言 在深度学习中&#xff0c;优化算法&#xff08;Optimizers&#xff09;用于更新神经网络的权重&#xff0c;以最小化损失函数&#xff08;Loss Function&#xff09;。一个高效的优化算法可以加速训练过程&#xff0c;并提高模型的性能和稳定…

【JVM详解四】执行引擎

一、概述 Java程序运行时&#xff0c;JVM会加载.class字节码文件&#xff0c;但是字节码并不能直接运行在操作系统之上&#xff0c;而JVM中的执行引擎就是负责将字节码转化为对应平台的机器码让CPU运行的组件。 执行引擎是JVM核心的组成部分之一。可以把JVM架构分成三部分&am…

route 与 router 之间的差别

简述&#xff1a; router&#xff1a;主要用于处理一些动作&#xff0c; route&#xff1a;主要获得或处理一些数据&#xff0c;比如地址、参数等 例&#xff1a; videoInfo1.vue&#xff1a; <template><div class"video-info"><h3>二级组件…

SamWaf开源轻量级的网站应用防火墙(安装包),私有化部署,加密本地存储的数据,易于启动,并支持 Linux 和 Windows 64 位和 Arm64

一、SamWaf轻量级开源防火墙介绍 &#xff08;文末提供下载&#xff09; SamWaf网站防火墙是一款适用于小公司、工作室和个人网站的开源轻量级网站防火墙&#xff0c;完全私有化部署&#xff0c;数据加密且仅保存本地&#xff0c;一键启动&#xff0c;支持Linux&#xff0c;Wi…

极客说|利用 Azure AI Agent Service 创建自定义 VS Code Chat participant

作者&#xff1a;卢建晖 - 微软高级云技术布道师 「极客说」 是一档专注 AI 时代开发者分享的专栏&#xff0c;我们邀请来自微软以及技术社区专家&#xff0c;带来最前沿的技术干货与实践经验。在这里&#xff0c;您将看到深度教程、最佳实践和创新解决方案。关注「极客说」&a…