玩转Mysql系列 - 第17篇:存储过程&自定义函数详解

2023-11-01

这是Mysql系列第17篇。

环境:mysql5.7.25,cmd命令中进行演示。

代码中被[]包含的表示可选,|符号分开的表示可选其一。

需求背景介绍

线上程序有时候出现问题导致数据错误的时候,如果比较紧急,我们可以写一个存储来快速修复这块的数据,然后再去修复程序,这种方式我们用到过不少。

存储过程相对于java程序对于java开发来说,可能并不是太好维护以及阅读,所以不建议在程序中去调用存储过程做一些业务操作。

关于自定义函数这块,若mysql内部自带的一些函数无法满足我们的需求的时候,我们可以自己开发一些自定义函数来使用。

所以建议大家掌握mysql中存储过程和自定义函数这块的内容。

本文内容

  • 详解存储过程的使用

  • 详解自定义函数的使用

准备数据

/*建库javacode2018*/
drop database if exists javacode2018;
create database javacode2018;

/*切换到javacode2018库*/
use javacode2018;

/*建表test1*/
DROP TABLE IF EXISTS t_user;
CREATE TABLE t_user (
  id   INT NOT NULL PRIMARY KEY COMMENT '编号',
  age  SMALLINT UNSIGNED NOT NULL COMMENT '年龄',
  name VARCHAR(16) NOT NULL COMMENT '姓名'
) COMMENT '用户表';

存储过程

概念

一组预编译好的sql语句集合,理解成批处理语句。

好处:

  • 提高代码的重用性

  • 简化操作

  • 减少编译次数并且减少和数据库服务器连接的次数,提高了效率。

创建存储过程

create procedure 存储过程名([参数模式] 参数名 参数类型)
begin
    存储过程体
end

参数模式有3种:

in:该参数可以作为输入,也就是该参数需要调用方传入值。

out:该参数可以作为输出,也就是说该参数可以作为返回值。

inout:该参数既可以作为输入也可以作为输出,也就是说该参数需要在调用的时候传入值,又可以作为返回值。

参数模式默认为IN。

一个存储过程可以有多个输入、多个输出、多个输入输出参数。

调用存储过程

call 存储过程名称(参数列表);

注意:调用存储过程关键字是call

删除存储过程

drop procedure [if exists] 存储过程名称;

存储过程只能一个个删除,不能批量删除。

if exists:表示存储过程存在的情况下删除。

修改存储过程

存储过程不能修改,若涉及到修改的,可以先删除,然后重建。

查看存储过程

show create procedure 存储过程名称;

可以查看存储过程详细创建语句。

示例

示例1:空参列表

创建存储过程

/*设置结束符为$*/
DELIMITER $
/*如果存储过程存在则删除*/
DROP PROCEDURE IF EXISTS proc1;
/*创建存储过程proc1*/
CREATE PROCEDURE proc1()
  BEGIN
    INSERT INTO t_user VALUES (1,30,'路人甲Java');
    INSERT INTO t_user VALUES (2,50,'刘德华');
  END $

/*将结束符置为;*/
DELIMITER ;

delimiter用来设置结束符,当mysql执行脚本的时候,遇到结束符的时候,会把结束符前面的所有语句作为一个整体运行,存储过程中的脚本有多个sql,但是需要作为一个整体运行,所以此处用到了delimiter。

mysql默认结束符是分号。

上面存储过程中向t_user表中插入了2条数据。

调用存储过程:

CALL proc1();

验证效果:

mysql> select * from t_user;
+----+-----+---------------+
| id | age | name          |
+----+-----+---------------+
|  1 |  30 | 路人甲Java    |
|  2 |  50 | 刘德华        |
+----+-----+---------------+
2 rows in set (0.00 sec)

存储过程调用成功,test1表成功插入了2条数据。

示例2:带in参数的存储过程

创建存储过程:

/*设置结束符为$*/
DELIMITER $
/*如果存储过程存在则删除*/
DROP PROCEDURE IF EXISTS proc2;
/*创建存储过程proc2*/
CREATE PROCEDURE proc2(id int,age int,in name varchar(16))
  BEGIN
    INSERT INTO t_user VALUES (id,age,name);
  END $

/*将结束符置为;*/
DELIMITER ;

调用存储过程:

/*创建了3个自定义变量*/
SELECT @id:=3,@age:=56,@name:='张学友';
/*调用存储过程*/
CALL proc2(@id,@age,@name);

验证效果:

mysql> select * from t_user;
+----+-----+---------------+
| id | age | name          |
+----+-----+---------------+
|  1 |  30 | 路人甲Java    |
|  2 |  50 | 刘德华        |
|  3 |  56 | 张学友        |
+----+-----+---------------+
3 rows in set (0.00 sec)

张学友插入成功。

示例3:带out参数的存储过程

创建存储过程:

delete a from t_user a where a.id = 4;
/*如果存储过程存在则删除*/
DROP PROCEDURE IF EXISTS proc3;
/*设置结束符为$*/
DELIMITER $
/*创建存储过程proc3*/
CREATE PROCEDURE proc3(id int,age int,in name varchar(16),out user_count int,out max_id INT)
  BEGIN
    INSERT INTO t_user VALUES (id,age,name);
    /*查询出t_user表的记录,放入user_count中,max_id用来存储t_user中最小的id*/
    SELECT COUNT(*),max(id) into user_count,max_id from t_user;
  END $

/*将结束符置为;*/
DELIMITER ;

proc3中前2个参数,没有指定参数模式,默认为in。

调用存储过程:

/*创建了3个自定义变量*/
SELECT @id:=4,@age:=55,@name:='郭富城';
/*调用存储过程*/
CALL proc3(@id,@age,@name,@user_count,@max_id);

验证效果:

mysql> select @user_count,@max_id;
+-------------+---------+
| @user_count | @max_id |
+-------------+---------+
|           4 |       4 |
+-------------+---------+
1 row in set (0.00 sec)
示例4:带inout参数的存储过程

创建存储过程:

/*如果存储过程存在则删除*/
DROP PROCEDURE IF EXISTS proc4;
/*设置结束符为$*/
DELIMITER $
/*创建存储过程proc4*/
CREATE PROCEDURE proc4(INOUT a int,INOUT b int)
  BEGIN
    SET a = a*2;
    select b*2 into b;
  END $

/*将结束符置为;*/
DELIMITER ;

调用存储过程:

/*创建了2个自定义变量*/
set @a=10,@b:=20;
/*调用存储过程*/
CALL proc4(@a,@b);

验证效果:

mysql> SELECT @a,@b;
+------+------+
| @a   | @b   |
+------+------+
|   20 |   40 |
+------+------+
1 row in set (0.00 sec)

上面的两个自定义变量@a、@b作为入参,然后在存储过程内部进行了修改,又作为了返回值。

示例5:查看存储过程
mysql> show create procedure proc4;
+-------+-------+-------+-------+-------+-------+
| Procedure | sql_mode | Create Procedure | character_set_client | collation_connection | Database Collation |
+-------+-------+-------+-------+-------+-------+
| proc4     | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | CREATE DEFINER=`root`@`localhost` PROCEDURE `proc4`(INOUT a int,INOUT b int)
BEGIN
    SET a = a*2;
    select b*2 into b;
  END | utf8                 | utf8_general_ci      | utf8_general_ci    |
+-------+-------+-------+-------+-------+-------+
1 row in set (0.00 sec)

函数

概念

一组预编译好的sql语句集合,理解成批处理语句。类似于java中的方法,但是必须有返回值。

创建函数

create function 函数名(参数名称 参数类型)
returns 返回值类型
begin
    函数体
end

参数是可选的。

返回值是必须的。

调用函数

select 函数名(实参列表);

删除函数

drop function [if exists] 函数名;

查看函数详细

show create function 函数名;

示例

示例1:无参函数

创建函数:

/*删除fun1*/
DROP FUNCTION IF EXISTS fun1;
/*设置结束符为$*/
DELIMITER $
/*创建函数*/
CREATE FUNCTION fun1()
  returns INT
  BEGIN
    DECLARE max_id int DEFAULT 0;
    SELECT max(id) INTO max_id FROM t_user;
    return max_id;
  END $
/*设置结束符为;*/
DELIMITER ;

调用看效果:

mysql> SELECT fun1();
+--------+
| fun1() |
+--------+
|      4 |
+--------+
1 row in set (0.00 sec)
示例2:有参函数

创建函数:

/*删除函数*/
DROP FUNCTION IF EXISTS get_user_id;
/*设置结束符为$*/
DELIMITER $
/*创建函数*/
CREATE FUNCTION get_user_id(v_name VARCHAR(16))
  returns INT
  BEGIN
    DECLARE r_id int;
    SELECT id INTO r_id FROM t_user WHERE name = v_name;
    return r_id;
  END $
/*设置结束符为;*/
DELIMITER ;

运行看效果:

mysql> SELECT get_user_id(name) from t_user;
+-------------------+
| get_user_id(name) |
+-------------------+
|                 1 |
|                 2 |
|                 3 |
|                 4 |
+-------------------+
4 rows in set (0.00 sec)

存储过程和函数的区别

存储过程的关键字为procedure,返回值可以有多个,调用时用call一般用于执行比较复杂的的过程体、更新、创建等语句

函数的关键字为function返回值必须有一个,调用用select,一般用于查询单个值并返回。

存储过程 函数
返回值 可以有0个或者多个 必须有一个
关键字 procedure function
调用方式 call select
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

玩转Mysql系列 - 第17篇:存储过程&自定义函数详解 的相关文章

  • Mysql:计算访问频率

    我有这张桌子 CREATE OR REPLACE TABLE hits ip bigint page VARCHAR 256 agent VARCHAR 1000 date datetime 我想计算每个页面的 googlebot 访问频率
  • 当我耗尽 bigint 生成的密钥时会发生什么?怎么处理呢?

    我自己无法想象一个好的答案 所以我想在这里问 在我心里 我总是想知道 如果AUTO INCREMENT PRIMARY ID我的专栏MySQL表用完了吗 举例来说 我有一个有两列的表 一个ID auto increment primary
  • 自动将范围内的值插入表中

    是否可以使用 MySQL 语句自动将值插入表中 即从 30 到 200 这是一个应该执行此操作的存储过程 CREATE PROCEDURE insert range BEGIN DECLARE i INT DEFAULT 30 WHILE
  • 未找到教义列:1054“字段列表”中未知列“s.features”

    我在站点表中添加了一个新列 features 并使用 Doctrine 重新生成了模型 此代码导致错误 siteTable Doctrine Core getTable Site site siteTable gt findOneByNam
  • MySQL 全文搜索之谜

    我们的网站上有一个使用 MySQL 全文搜索的简单搜索 但由于某种原因 它似乎没有返回正确的结果 我不知道这是否是 Amazon RDS 我们的数据库服务器所在的位置 或我们请求的查询的某种问题 这是数据库表的结构 CREATE TABLE
  • 解析错误:语法错误,意外的“”(T_ENCAPSED_AND_WHITESPACE)[重复]

    这个问题在这里已经有答案了 完整错误 解析错误 语法错误 意外的 T ENCAPSED AND WHITESPACE 需要标识符 T STRING 或 变量 T VARIABLE 或数字 T NUM STRING 它说错误出现在第 12 行
  • MySQL:记录之间的平均间隔

    假设这张表 id date 1 2010 12 12 2 2010 12 13 3 2010 12 18 4 2010 12 22 5 2010 12 23 如何仅使用 MySQL 查询找到这些日期之间的平均间隔 例如 此表上的计算将是 2
  • 可以有多个用户作为 MySQL 存储过程的定义者吗?

    我在 MySQL 存储过程方面遇到了一些困难 并且感到有点沮丧 我有一组由 Bob 创建的 SP 由于他是定义者 只有他才能看到它们的 CREATE 语句 修改它们等 Mary 可以在 MySQL Workbench 的架构中看到 Bob
  • MySQL - 替换列中的字符

    作为一个自学成才的新手 我给自己制造了一个大问题 在将数据插入数据库之前 我将字符串中的撇号 转换为双引号 而不是 MySQL 实际需要的反斜杠和撇号 在我的表增长到超过 200 000 行之前 我认为最好立即纠正此问题 所以我做了一些研究
  • 展平具有未知列数的子/父数据

    我正在努力寻找存储和表示 SQL MySQL DB 和 C Windows 表单中的数据的最佳方法 我的数据映射到如下所示的类时 public class Parent public string UniqueID get set Key
  • iPhone表情插入MySQL却变成空值

    我们正在开发一个 iPhone 应用程序 它将表情符号从 iPhone 发送到服务器端 PHP 并插入到 MySQL 表中 我正在做服务器端的工作 但是insert语句执行成功后 插入的值变成空了 我可以正确插入字段 varchar 的是文
  • ORDER BY id 或 date_created 显示最新结果?

    我有一个表 实际上有几个 我想首先从中获取最新条目的结果 这是我的ORDER BY条款选项 date created INT 从不改变值 id 当然是INT AUTO INCRMENT 两列应同等地代表记录插入的顺序 我自然会使用date
  • 将程序存储在 phpMyAdmin 中

    我必须将存储过程添加到 MySQL 数据库 问题是托管提供php我的管理员来管理数据库 我在网上搜索了一下 想法是运行创建程序的MySQL本机语句 但由于程序的代码通常可能有 我们必须更改 MySQL 中的分隔符 php我的管理员没有这个选
  • PHP mysql_num_rows 死错误

    我想创建一个页面 用户可以在其中添加他们的信息 我已经创建了该页面 但我真正的问题是代码 我有一些问题 这部分代码
  • 如何在php中正确显示另一种语言的mysql表数据

    我有一个 mySQL 表 其中一列中的数据采用英语以外的语言 波斯语 当我在表中输入数据时 它会正确显示 但是当我想在 php 文件中显示数据时 它会显示如下 好吧 我应该怎么做才能以正确的形式显示数据 由于我经常使用 非英语 字符 因此要
  • 表已满(使用 MEMORY 引擎)

    我想将生产数据库传输到我的开发机器上进行测试 它有 6 张桌子MEMORY出于性能目的的引擎 I did mysqldump routines hxxx uxxx pxxx prod database gt prod dump sql 当我
  • mysql 在 sum() 函数上使用 concat,例如 concat(sum(col1),"%")

    我正在尝试合并多个查询 但其中一个查询使用 sum 当我尝试在此列上应用 concat 时 我得到不需要的 blob 结果 我如何在聚合列上应用 concat 和 union 我期待这个结果 SELECT row 1 col1 UNION
  • 将错误保存到 MySQL 数据库

    我有一个 php 查询来更新 MySQL 数据库 请参见下文 sql update hr payroll set payroll number payroll number tax code tax bacs ref bacs ref pa
  • Mysql获取特定表的最后一个id

    我必须从特定的插入表中获取最后的插入 ID 可以说我有这个代码 INSERT INTO blahblah test1 test 2 VALUES test1 test2 INSERT INTO blahblah2 test1 test 2
  • 为什么我的浮点数大于 1 时在 MYSQL 中存储为 .9999?

    我将进程时间作为 float 4 4 存储在 MySQL 数据库中 start time microtime TRUE things happen in my script end time microtime TRUE process t

随机推荐

  • ubuntu22安装和卸载nvidia驱动

    一 安装nvidia驱动 查看可以安装的版本 ubuntu drivers devices 选择安装nvidia driver 515 sudo apt install nvidia driver 515 重启 sudo reboot 验证
  • 服务器系统兼容性问题,微软表示因兼容性问题,部分用户无法升到Windows10最新版本...

    微软已警告Windows 10用户 由于英特尔Thunderbolt NVMe SSD的兼容性问题 他们可能被禁止升级到Windows 10版本2004或20H2 每当Microsoft发布新功能更新时 即使是次要功能更新 例如Window
  • SpringBoot3集成Kafka

    标签 Kafka3 Kafka eagle3 一 简介 Kafka是一个开源的分布式事件流平台 常被用于高性能数据管道 流分析 数据集成和关键任务应用 基于Zookeeper协调的处理平台 也是一种消息系统 具有更好的吞吐量 内置分区 复制
  • 【Vue3】vite打包报错:块的大小超过限制,Some chunks are larger than 500kb after minification

    问题描述 vite打包报错 块的大小超过限制 Some chunks are larger than 500kb after minification 解决方法 1 加大限制的大小将500kb改成1000kb或者更大 chunkSizeWa
  • 2022.6.1 C++——类型设计与实例化对象

    对象的创建与使用 对象的创建与使用 1 直接定义类的实例 对象 2 C 对象模型讨论 3 this指针的作用 对象是类的实例 声明一种数据类型只是告诉编译系统该数据类型的构造 并没有预定内存 类只是一个样板 图纸 以此样板可以在内存中开辟出
  • java 使用jdbc向mysql数据库中插入1亿条数据

    http blog csdn net home zhang article details 50836253 java view plain copy
  • 弱网压测环境 - tcconfig

    弱网压测环境 tcconfig 服务器性能指标 服务器接口的容错机制及重连机制需正常 服务器之间的网络通信需正常 服务器存储数据需一致及准确 请求不发生堆积 数据不发生错乱 弱网指标 带宽 吞吐量 单位时间内传输的数据量 单位通常是 每秒比
  • ROSE笔记-ctf.show_web2-WP

    ctf show web2 WP 直接是一个登录界面 在用户名处输入万能密码 admin or 1 1 显示了登陆信息 现在就是去找回显位置 用order by判断当前查询的列数 order by 4的时候登陆信息消失 而order by
  • 根据Modeller官网教程进行单模板建模

    Tutorial Basic Modeling https salilab org modeller tutorial basic html 1 搜索相关序列 从官网下载源文件 分析 TvLDH ali 存放目标序列 需满足要求的格式 gt
  • 异常处理函数set_exception_handler

    由于历史原因 php一开始被设计为一门面向过程的语言 所以异常处理没有使用像Java一样的 try catch 机制 出错时直接显示到页面上 或者记录到web服务器的错误日志中 并且php的错误分成了很多的级别 例如E ERROR E WA
  • 斐波那契数列(递归改进)

    题目 求斐波那契数列的第n项 写一个函数 输入n 求斐波那契数列的第n项 斐波那契数列的定义如下 大多数人看到后第一时间都会写出如下代码 递归 方法直观但时间效率低 long long Fibonacci unsigned int n if
  • 远程桌面连接不能复制粘贴怎么办 远程控制电脑无法复制粘贴的解决方法

    解决方法如下 第一步 打开远程桌面连接 点开电脑左下角的开始菜单 找到远程桌面连接 点开 如果你不常用远程桌面连接 那么这个图标就在附件里面 仔细找找就看到了 第二步 点开远程桌面连接的对话框 在对话框的左下角找到 显示选项 点开它 第三步
  • 数据加密标准(DES)概念及工作原理

    0x01 数据加密标准DES介绍 数据加密标准 Data Encryption Standard DES 是一种用于加密数字数据的对称密钥算法 密钥长度为56位 安全性不强 但它在密码学的进步中具有很大的影响力 0x02 数据加密标准历史
  • MySQL 锁

    文章目录 1 锁的种类 2 按兼容性划分 1 共享锁 2 排他锁 3 按锁粒度划分 1 表锁 2 行锁 3 注意 4 按锁模式划分 1 记录锁 2 间隙锁 3 临键锁 4 插入意向锁 5 意向锁 5 按加锁机制划分 1 悲观锁 2 乐观锁
  • 支付宝小程序集成mqtt兼容IOS和安卓

    1 前言 去年就想做支付宝小程序接入mqtt协议 但最终多方咨询 问客服问社区得到的答案都是支付宝小程序不能直接支持mqtt协议 偶然间发现徐宏大神的佳作 终于发现了xmqtt js这个好东西 它实现了支付宝小程序完美接入mqtt协议 设备
  • where、having、group by、order by、limit的区别和使用顺序

    where having group by order by limit的区别和使用顺序 姚文斌的博客 CSDN博客
  • 怎么让别人连接自己的数据库(MySQL)

    怎么让别人连接自己的数据库 MySQL update user set host where user root and host localhost flush privileges
  • 实现领域驱动设计----第一章

    带着问题上路 什么是领域驱动设计 是什么 为什么要做领域驱动设计 为什么要做 怎样做领域驱动设计 怎样做 其他的设计模式与领域驱动设计的区别 有类似为什么要做 但是是在取长补短的总结 译者序 就像在20世纪六七十年代出现了软件危机之后 面向
  • LINK : fatal error LNK1104: 无法打开文件“XXXXX.lib”解决方法

    1 首先我们一开始是配置包含的库目录 2 找到我们缺少XXXX lib对应的目录 确定 3 然后在链接器 输入 附加的依赖项中我们输入这个lib文件的全名 这一步按照实际情况添加 然后编译链接即可 主要原理分析 1 报错提示找不到这个lib
  • 玩转Mysql系列 - 第17篇:存储过程&自定义函数详解

    这是Mysql系列第17篇 环境 mysql5 7 25 cmd命令中进行演示 代码中被 包含的表示可选 符号分开的表示可选其一 需求背景介绍 线上程序有时候出现问题导致数据错误的时候 如果比较紧急 我们可以写一个存储来快速修复这块的数据