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,一经查实,立即删除!

相关文章

【力扣 28】找出字符串中第一个匹配项的下标 C++题解(字符串匹配)

给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 示例 1&#xff1a; 输入&#xff1a;haystack “s…

(13)DroneCAN 适配器节点(二)

文章目录 前言 2 固件 2.1 基于F103 2.2 基于F303 2.3 基于F431 3 ArduPilot固件DroneCAN设置 3.1 f303-通用设置示例 4 DroneCAN适配器节点 前言 这些节点允许现有的 ArduPilot 支持的外围设备作为 DroneCAN 或 MSP 设备适应 CAN 总线。这也允许扩展自动驾驶仪硬件的…

随机文本生成器

目录 开头程序程序的流程图程序打印的效果(不必细看&#xff0c;因为字符太多)例1例2例3 结尾 开头 大家好&#xff0c;我叫这是我58。看&#xff01;这下面有一个程序。 程序 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <random> #includ…

快递物流仓库管理系统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…

R-CNN和YOLO的各自优缺点

R-CNN&#xff08;包括其改进版本如Faster R-CNN和Mask R-CNN&#xff09;与YOLO&#xff08;You Only Look Once&#xff09;是两种常用的物体检测算法&#xff0c;它们各自有不同的优缺点&#xff0c;适用于不同的应用场景和需求。 R-CNN 系列 优点&#xff1a; 高精度&am…

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

后端部署 第一步配置自己的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 局限性…

Java的多彩之旅

Java的多彩之旅&#xff0c;确实是一场技术与创新的盛宴。下面&#xff0c;我们将探索它如何在不同领域展现其魅力和功能&#xff0c;从基础到前沿&#xff0c;一步步揭开Java的神秘面纱。 基础开发&#xff1a;清新之源 Java的基础语法简洁而严谨&#xff0c;是学习之旅的起…

Mongodb的体系结构,语法,底层原理,怎么开发使用,使用场景有哪些?

MongoDB 教材 MongoDB 是一个开源的 NoSQL 数据库&#xff0c;以其高性能、高可用性和自动扩展性广受欢迎。本文将详细介绍 MongoDB 的体系结构、语法、底层原理、开发使用方法及常见使用场景。 目录 MongoDB 简介MongoDB 体系结构MongoDB 语法 基本操作高级查询聚合操作 底…

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…