MySQL进阶:存储过程和函数

存储过程和函数

  • 1. 简介
  • 2. 创建存储过程
    • 使用MySQL工作台创建存储过程
  • 3. 删除存储过程
  • 4. 参数
    • 带默认值的参数
    • 参数验证
    • 输出参数
  • 5. 变量
  • 6. 函数
  • 7. 其他约定

1. 简介

存储过程三大作用:

  1. 储存和管理SQL代码(置于数据库中,与应用层分离,同视图和函数一样,都是增加抽象层,作为模块化抽象工具)
  2. 数据安全
  3. 性能优化

假设你要开发一个使用数据库的应用程序,你应该将SQL语句写在哪里呢?
如果将SQL语句内嵌在应用程序的代码里,将使其混乱且难以维护,所以应该将SQL代码和应用程序代码分开,将SQL代码储存在所属的数据库中,具体来说,是放在储存过程(stored procedure)和函数中。

使用储存程序还有另外两个好处。首先,大部分DBMS会对储存过程中的代码进行一些优化,因此有时储存的SQL代码执行起来会更快。此外,就像视图一样,储存过程能加强数据安全。比如,我们可以移除对所有原始表的访问权限,让各种增删改的操作都通过储存过程来完成,然后就可以决定谁可以执行何种储存过程,用以限制用户对我们数据的操作范围,例如,防止特定的用户删除数据。
所以,储存过程很有用。

2. 创建存储过程

语法规则:

[DELIMITER $$]
-- delimiter 定界符;分隔符
CREATE PROCEDURE 储存过程名()
BEGIN
……;
……;
……;
END[$$]
[DELIMITER ;]

NOTE:

  1. MySQL中需要将储存过程主体内部的语句分隔符与SQL本身执行层面的语句分隔符 ; 区别开。要先用 DELIMITER(分隔符)关键字暂时将 SQL 语句的默认分隔符改为双美元符号 $ $ 或双斜杠 // 等,创建储存过程结束后再改回来。注意创建储存过程本身也是一个完整 SQL 语句,所以别忘了在 END 后要加一个暂时语句分隔符 ‘$$’。
  2. BEGIN 和 END 之间包裹的是此储存过程(PROCEDURE)的主体(body),主体里可以有多个语句,但每个语句都要以 ; 结束,包括最后一个。
  3. 调用此程序:点击闪电按钮或者用CALL关键字。大多数时候是在应用程序中调用。
DELIMITER $$
CREATE PROCEDURE get_invoices_with_balance()
BEGIN
SELECT *
FROM clinet_balance
WHERE balance > 0;
END$$
DELIMITER ;

使用MySQL工作台创建存储过程

也可以用点击的方式创造储存过程,右键选择 Create Stored Procedure,填空,Apply。这种方式Workbench会帮你处理暂时修改分隔符的问题。

3. 删除存储过程

标准模板:

DROP PROCEDURE IF EXISTS get_clients;
-- 注意加上IF EXISTS,以免因为此储存过程不存在而报错
DELIMITER $$
CREATE PROCEDURE get_clients()
BEGIN
SELECT * FROM clients;
END$$
DELIMITER ;
CALL get_clients()

Note:最好把删除和创建每一个储存过程的代码也储存在不同的SQL文件中,并把这样的文件放在Git这样的源码控制下,这样就能与其它团队成员共享Git储存库。他们就能在自己的机器上重建(复现)数据库以及该数据库下的所有的视图和储存过程参数

4. 参数

模板:

CREATE PROCEDURE 储存过程名(
参数1 数据类型,
参数2 数据类型,
……) 
BEGIN
……;
END

例子:

USE sql_invoicing;
DROP PROCEDURE IF EXISTS get_clients_by_state;
DELIMITER $$
CREATE PROCEDURE get_clients_by_state(state CHAR(2))   -- 一般用VARCHAR,除非可以确定字符的个数
BEGINSELECT * FROM clients c   -- 采用别名的形式来引用参数,也可用前缀和后缀WHERE c.state = state;    -- 不能采用相同的别名来命名,如state = state
END $$
DELIMITER ;

带默认值的参数

给参数设置默认值,主要是运用条件语句块和替换空值函数。
SQL中的条件类语句:

  1. 替换空值 IFNULL(值1,值2);
  2. IF函数 IF(条件表达式, 返回值1, 返回值2)
  3. IF语句
    在这里插入图片描述
  4. CASE语句
    在这里插入图片描述
CREATE PROCEDURE get_clients_by_state( -- 尽量不用黄色箭头调用,传参数会出错。用CALL调用state CHAR(2))
BEGINIF state IS NULL THENSET state = 'CA';END IF;SELECT * FROM clients cWHERE c.state = state;
ENDCREATE PROCEDURE get_clients_by_state(state CHAR(2))
BEGINSELECT * FROM clients cWHERE c.state = IFNULL(state, c.state);
END

注意一个区别:

  1. Parameter 形参(形式参数):创建储存过程中用的占位符,如 client_id、payment_method_id
  2. Argument 实参(实际参数):调用时实际传入的值,如 1、3、5、NULL

参数验证

使用方法:储存过程除了可以查,也可以增删改,但修改数据前最好先进行参数验证以防止不合理的修改。主要利用 IF THEN条件语句和 SIGNAL SQLSTATE/MESSAGE_TEXT 关键字。

具体的错误类型可通过谷歌 “sqlstate error” 查阅(推荐使用IBM的那个表),这里是 ‘22 Data Exception’ 大类中的 ‘22003 A numeric value is out of range.’ 类型。
在这里插入图片描述

CREATE DEFINER=`root`@`localhost` PROCEDURE `make_payment`(invoice_id INT,payment_amount DECIMAL(9,2),/*9是精度(存储的有效位数), 2是小数位数。见:https://dev.mysql.com/doc/refman/8.0/en/fixed-point-types.html*/payment_date DATE)
BEGINIF payment_amount <= 0 THENSIGNAL SQLSTATE '22003'SET MESSAGE_TEXT = 'Invalid payment amount';UPDATE invoices iSETi.payment_total = payment_amount,i.payment_date = payment_dateWHERE i.invoice_id = invoice_id;
END

Note:过犹不及,加入过多的参数验证会让代码过于复杂难以维护,像payment_amount 非空这样的验证就不需要添加因为 payment_amount 字段本身就不允许空值因此MySQL 会自动报错。参数验证工作更多的应该在应用程序端接受用户输入数据时就检测和报告,那样更快也更有效。储存过程里的参数验证只是在有人越过应用程序直接访问储存过程时作为最后的防线。这里只应该写那些最关键和必要的参数验证。

输出参数

输入参数是用来给储存过程传入值的,我们也可以用输出参数(变量)来获取储存程序的值.

  • 使用方法:具体是在参数的前面加上 OUT 关键字,然后再 SELECT 后加上 INTO……
    调用麻烦,如无需要,不要多此一举
CREATE DEFINER=`root`@`localhost` PROCEDURE `get_unpaid_invoices_for_client`(client_id INT,OUT invoice_count INT,OUT invoice_total DECIMAL(9,2))-- 默认是输入参数,输出参数要加OUT前缀
BEGINSELECT COUNT(*),SUM(invoice_total)INTO invoice_count, invoice_total-- SELECT后跟上INTO语句将SELECT选出的值传入输出参数(输出变量)中FROM invoices iWHEREi.client_id = client_id ANDpayment_total = 0;
END

通过输出参数获取并读取数据有些麻烦,若无充足的原因,不要多此一举。

5. 变量

两种变量:

  1. 用户或会话变量 SET @变量名 = ……
    用 SET 语句并在变量名前加 @ 前缀来定义,将在整个用户会话期间存续,在会话结束断开MySQL连接时才被清空,这种变量主要在调用带输出变量的储存过程时使用,用来传入储存过程作为输出参数来获取结果值。
  2. 本地变量 DECLARE 变量名 数据类型 [DEFAULT 默认值]
    在储存过程或函数中通过 DECLARE 声明并使用,在函数或储存过程执行结束时就被清空,常用来执行储存过程(或函数)中的计算。
CREATE PROCEDURE  get_risk_factor ()
BEGIN-- 声明三个本地变量,可设默认值DECLARE risk_factor DECIMAL(9,2) DEFAULT 0;DECLARE invoices_total DECIMAL(9,2);DECLARE invoices_count INT;-- 用SELECT得到需要的值并用INTO传入变量SELECT SUM(invoice_total), COUNT(*)FROM invoices;-- 用SET语句给risk_factor计算赋值SET risk_factor = invoices_total/invoices_count * 5;-- 用SELECT语句将结果展示出来SELECT risk_factor;
END

6. 函数

函数和储存过程的作用非常相似,唯一区别是函数只能返回单一值而不能返回多行多列的结果集,当你只需要返回一个值时就可以创建函数。区别:

  1. 参数设置和 body 主体之间,有一段确定返回值类型以及函数属性的语句段。
  2. 最后是返回(RETURN)值而不是查询(SELECT)值。
  • 删除语法:DROP FUNCTION IF EXISTS。

关于函数属性的说明:

  1. DETERMINISTIC 决定性的,唯一输入决定唯一输出,和数据的改动更新无关,比如税收是订单总额的10%,则以订单总额为输入、税收为输出的函数就是决定性的,但这里每个顾客的 risk_factor 会随着其发票记录的增加、更新而改变,所以不是 DETERMINISTIC 的
  2. READS SQL DATA 需要用到 SELECT 语句进行数据读取的函数,几乎所有函数都满足
  3. MODIFIES SQL DATA 函数中有 增删改 或者说有 INSERT DELETE UPDATE 语句,这个例子不需要。
CREATE DEFINER=`root`@`localhost` FUNCTION `get_risk_factor_for_clients`(client_id INT) RETURNS int
READS SQL DATA
BEGINDECLARE risk_factor DECIMAL(9,2) DEFAULT 0;DECLARE invoices_total DECIMAL(9,2);DECLARE invoices_count INT;SELECT SUM(invoice_total), COUNT(*)INTO invoices_total, invoices_countFROM invoices iWHERE i.client_id = client_id;SET risk_factor = invoices_total/invoices_count * 5;RETURN IFNULL(risk_factor, 0);
END

7. 其他约定

一些命名规则:

  1. 函数前加上fn前缀;
  2. 存储过程加上proc前缀
  3. 命名采用驼峰式:如procGetRiskFactor
  4. 不采用驼峰式,则采用下划线如:get_risk_factor
  5. 分隔符,有人用$$,有人用//
  6. 入乡随俗,遵守已经有的约定

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

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

相关文章

快递物流仓库管理系统java项目springboot和vue的前后端分离系统java课程设计java毕业设计

文章目录 快递物流仓库管理系统一、项目演示二、项目介绍三、部分功能截图四、部分代码展示五、底部获取项目源码&#xff08;9.9&#xffe5;带走&#xff09; 快递物流仓库管理系统 一、项目演示 快递物流仓库管理系统 二、项目介绍 语言: Java 数据库&#xff1a;MySQL 前…

宝塔安装rabbitMQ实战

服务器环境说明 阿里云服务器、宝塔、centos7 一、下载erlang 原因&#xff1a;RabbitMQ服务端代码是使用并发式语言Erlang编写的&#xff0c;安装Rabbit MQ的前提是安装Erlang。 下载地址&#xff1a;http://www.erlang.org/downloads 下载对应的版本&…

山东省著名烈士孙善师孙善帅故居布展喜添新篇

人海信息网山东讯&#xff08;张春兄、冯爱云&#xff09; “……他们以钢铁般的意志&#xff0c;坚守共产党员的使命&#xff0c;他们就是泺口九烈士的孙善师孙善帅兄弟&#xff01;”6月28日&#xff0c;对于山东省著名烈士孙善师孙善帅故居来说&#xff0c;又是一个不平凡的…

LabVIEW电压电流实时监测系统

开发了一种基于LabVIEW和研华&#xff08;Advantech&#xff09;数据采集卡的电压电流实时监测系统&#xff0c;通过高效的数据采集和处理&#xff0c;为工业和科研用户提供高精度、实时的电压电流监测解决方案。系统采用研华USB-4711A数据采集卡&#xff0c;结合LabVIEW编程环…

AI论文速读 | 2024[KDD]自适应时空图神经网络中图中奖彩票的预训练识别

题目&#xff1a;Pre-Training Identification of Graph Winning Tickets in Adaptive Spatial-Temporal Graph Neural Networks 作者&#xff1a;Wenying Duan, Tianxiang Fang, Hong Rao, Xiaoxi He 机构&#xff1a;南昌大学&#xff0c;澳门大学 arXiv网址&#xff1a;h…

Python数据分析-股票分析和可视化(深证指数)

一、内容简介 股市指数作为衡量股市整体表现的重要工具&#xff0c;不仅反映了市场的即时状态&#xff0c;也提供了经济健康状况的关键信号。在全球经济体系中&#xff0c;股市指数被广泛用于预测经济活动&#xff0c;评估投资环境&#xff0c;以及制定财政和货币政策。在中国…

IEEE JSTSP综述:从信号处理领域分析视触觉传感器的研究

触觉传感器是机器人系统的重要组成部分&#xff0c;虽然与视觉相比触觉具有较小的感知面积&#xff0c;但却可以提供机器人与物体交互过程中更加真实的物理信息。 视觉触觉传感是一种分辨率高、成本低的触觉感知技术&#xff0c;被广泛应用于分类、抓取、操作等领域中。近期&a…

如何跑起来一个前后端项目

后端部署 第一步配置自己的maven 第二步优先导入自己本地jar包当本地没有在从远程下载 第三步找到配置文件 第四步成功运行后端部署完毕 前端部署 第一步看看项目node_modules有没有文件如果有就是已经安装好了对应的依赖&#xff0c;没有执行npm install 第二步运行即可

决策树划分属性依据

划分依据 基尼系数基尼系数的应用信息熵信息增益信息增益的使用信息增益准则的局限性 最近在学习项目的时候经常用到随机森林&#xff0c;所以对决策树进行探索学习。 基尼系数 基尼系数用来判断不确定性或不纯度&#xff0c;数值范围在0~0.5之间&#xff0c;数值越低&#x…

【知识学习】Unity3D中Scriptable Render Pipeline的概念及使用方法示例

Unity3D中的Scriptable Render Pipeline&#xff08;SRP&#xff09;是一种高度可定制的渲染管线框架&#xff0c;允许开发者完全控制渲染流程&#xff0c;以适应不同的渲染需求和硬件平台。SRP使得开发者可以编写自己的渲染逻辑&#xff0c;包括摄像机管理、渲染设置、光照处理…

【机器学习】K-means++: 一种改进的聚类算法详解

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 K-means: 一种改进的聚类算法详解引言1. K-means算法回顾1.1 基本概念1.2 局限性…

RDMA建链的3次握手和断链的4次挥手流程?

文章目录 基础信息建链 3次握手断链4次挥手建联状态active端passive端 报文结构函数关系其他后记 基础信息 CM: Communication Management 通信管理 连接管理SIDR: Service ID Resolution Protocol. 作用&#xff1a; enables users of Unreliable Datagram service to locate …

实验4 图像空间滤波

1. 实验目的 ①掌握图像空间滤波的主要原理与方法&#xff1b; ②掌握图像边缘提取的主要原理和方法&#xff1b; ③了解空间滤波在图像处理和机器学习中的应用。 2. 实验内容 ①调用 Matlab / Python OpenCV中的函数&#xff0c;实现均值滤波、高斯滤波、中值滤波等。 ②调…

【操作系统期末速成】 EP02 | 学习笔记(基于五道口一只鸭)

文章目录 一、前言&#x1f680;&#x1f680;&#x1f680;二、正文&#xff1a;☀️☀️☀️2.1 考点二&#xff1a;操作系统的功能及接口2.2 考点三&#xff1a;操作系统的发展及分类2.3 考点四&#xff1a;操作系统的运行环境&#xff08;重要&#xff09; 一、前言&#x…

从零开始三天学会微信小程序开发(三)

看到不少入门的小程序开发者不断的问重复性的问题&#xff0c;我们从实战角度开发了这个课程&#xff0c;希望能够帮助大家了解小程序开发。 课程分三天&#xff1a; 第一天&#xff1a;微信小程序开发入门第二天&#xff1a;给小程序接入云端数据第三天&#xff1a;完善我的…

MySQL高级-MVCC- readview介绍

文章目录 1、介绍2、ReadView中包含了四个核心字段&#xff1a;3、版本链数据的访问规则&#xff1a;4、不同的隔离级别&#xff0c;生成ReadView的时机不同&#xff1a; 1、介绍 ReadView&#xff08;读视图&#xff09;是 快照读 SQL执行时MVCC提取数据的依据&#xff0c;记录…

【计算机组成原理实验】——运算器组成实验

计组TEC4实验——运算器组成实验 1. 实验目的 (1&#xff09;掌握算术逻辑运算加、减、乘、与的工作原理。 (2) 熟悉简单运算器的数据传送通路。 (3) 验证实验台运算器的8位加、减、与、直通功能。 (4) 验证实验台的4位乘4位功能。 (5) 按给定数据&#xff0c;完成几种指…

SerDes介绍以及原语使用介绍(4)ISERDESE2原语仿真

文章目录 前言一、iserdese2_module模块二、oserdese2_module模块三、顶层模块四、仿真结果分析 前言 上文详细介绍了ISERDESE2原语的使用&#xff0c;本文根据仿真对ISERDESE2原语的使用进一步加深印象。在仿真时&#xff0c;与OSERDESE进行回环。 一、iserdese2_module模块…

昇思MindSpore学习笔记4--数据集 Dataset

昇思MindSpore学习笔记4--数据集 Dataset 摘要&#xff1a; 昇思MindSpore数据集Dataset的加载、数据集常见操作和自定义数据集方法。 一、数据集 Dataset概念 MindSpore数据引擎基于Pipeline 数据预处理相关模块&#xff1a; 数据集Dataset加载原始数据&#xff0c;支持文本…

大创项目推荐 题目:基于机器视觉的图像矫正 (以车牌识别为例) - 图像畸变校正

文章目录 0 简介1 思路简介1.1 车牌定位1.2 畸变校正 2 代码实现2.1 车牌定位2.1.1 通过颜色特征选定可疑区域2.1.2 寻找车牌外围轮廓2.1.3 车牌区域定位 2.2 畸变校正2.2.1 畸变后车牌顶点定位2.2.2 校正 7 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享…