给SQL打个CALL~
各位好久不见~【突然出现!
可能大家以为我这几天在偷懒,但其实···
我只是在沉迷zsh而已。【正色
上次macOS系统从bash更新至zsh之后我果然忘记把里面配置一起更新了~
今天要讲一个相对复杂但非常好用然而学校并没有正式教授的东西。
存储过程。而它彻底依赖线上编译似乎有些困难,目前我借助了Terminal进行本地的MySQL编写。#论发现自己配置没更新的正确起因
作为一个完美主义者(不是),我满心希望在Terminal写出来的东西是这样的效果:
或者至少是这样的:
然而···
它是这样的···
研究了两三天竟然毫无头绪呢。
不过至少它能用,嗯。
打CALL的理由
在我们讲解视图的时候便可以注意到,SQL的语句有些时候会变得非常繁琐。比如当我们处理订单的时候,我们实际上需要
- 确认库存是否足够;
- 减少库存以正确反映接受预定后的数量;
- 建立发货单;
- 联系顾客提供运送信息;
- 若是库存短缺,则要找到供应商补货
- ……
如果接到订单的每一次我们都需要重复以上的编码,这工作也过于单调且无趣了。
若是我们可以
把流程分门别类地建立起一个“模版”,这不但会大幅便捷我们的操作,统一我们的代码以
保证数据的一致性,还可以
简化对变动的管理。
简单、安全、高性能,简直完美~
这就是储存过程。
那么我们应该如何使用它呢?
打个CALL
首先要提到一点的是,
储存过程比一般的基本语句要难,使用它时会要求有更高的经验以及技能。
因此,若是一时没能理解或是顺利地对其进行编写也不必灰心丧气,毕竟不管什么事情都需要积累。【突然开始安慰自己
MySQL称存储过程的执行为调用,因此MySQL执行存储过程的语句为CALL。CALL接受存储过程的名字以及需要传递给它的任意参数:
CALL
存储过程可以显示结果,也可以不显示结果。
创建存储过程也遵循了SQL语句一贯的“简单粗暴”,即为create(创建)procedure(过程):
CREATE
如果存储过程接受参数,它们将在( )中列举出来;若是存储过程没有参数,后跟的( )仍然需要。
这里需要注意的是两个分号“;”(储存内容以及END)。
默认的MySQL语句分隔符为分号“;”。如果命令行实用程序要解释存储过程自身内的“;”字符,则它们最终不会成为存储过程的成分,这会使存储过程中的SQL出现句法错误。
解决办法是临时
更改命令行实用程序的语句分隔符:
DELIMITER
这样,存储过程体内的“;”无需变动,并且可以正确地传递给数据库引擎。
除“”符号外,任何字符都可以用作语句分隔符。
删除储存内容的方法也很简单,如同删除表格一般使用DROP语句即可:
DROP
创建储存内容举例 假如我们想一口气知道产品的平均价,最低价以及最高价,我们可以先将其创建(CREATE)储存内容(PROCEDURE):
DELIMITER
然后对其调取(CALL):
CALL
注意,我们在这里其实并没有刻意列出想要的参数。
变量参上
刚才的例子只是一个简单的存储过程,它简单地显示SELECT语句的结果。一般,存储过程并不显示结果,而是把结果返回给你指定的变量。
变量(variable)指的是内存中一个特定的“位置”,用来临时存储数据。个人觉得可以把它想像成之前十八年寒窗苦读时在数学解题中设的x。
参数举例储存过程名称不允许有重复,因此我们若是想用相同的名称命名新储存过程的话,首先需要将方才创建的储存过程删去:
DROP
接着,我们来创建一个接受三个参数的储存过程:
DELIMITER
为了方便起见,这里低价(price low)、高价(price high)以及均价(price average)分别用了pl、ph、pa代替。
关键字OUT指出相应的参数用来从存储过程传出一个值(返回给调用者)。
MySQL支持三种类型的参数:
- IN(传递给存储过程);
- OUT(从存储过程传出);
- INOUT(对存储过程传入和传出)。
存储过程的代码位于BEGIN和END语句内,由一系列SELECT语句组成,以检索值,然后通过指定INTO关键字保存到相应的变量。
注意,记录集不是允许的类型,因此不能通过一个参数返回多个行和列。为了调用加入了参数的储存过程,必须指定相同数量的变量名:
CALL
所有MySQL变量都必须以@开始。
变量举例如上所述,为调用此修改过的存储过程,我们必须指定3个变量名:
CALL
在调用时,这条语句并不显示任何数据。它返回以后可以显示(或在其他处理中使用)的变量。
SELECT @最低价;
我们当然也可以把三个一口气都列出来:
SELECT
干净整齐。
省心智能化
现在大家可能都会有些疑惑:
- 没觉得这样折腾会方便多少啊?
- 可能还是直接用SELECT语句更快?
- 将那些原本简单的SELECT语句封装起来,不是反而使简单的事情复杂化了?
是的没错,其实那些小打小闹对于储存过程来说,颇有些“杀鸡焉用牛刀”之感。
只有在存储过程内包含业务规则和智能处理时,它的威力才可以真正显现出来。假如我们想要知道一笔订单的总价,并且需要根据实际情况来增加营业税,那么我们应该怎么做?
按照过去的经验,若是我们单纯想要知道订单合计:
SELECT
如果要增加营业税的的话,只需在总价的基础上加工即可:
SELECT
思路不难,操作···似乎也不是很困难。
智能存储过程举例但如果有一个模版可以让我们更轻松地应付该工作,那会是什么样的?
输入我们想要计算的订单号,以及该订单是否需要打税,然后SQL自动返回该订单的总计。
DELIMITER
假如我们想知道订单号为20005且需要交税的订单总价:
CALL
假如我们想知道订单号为20005但不需要交税的订单总价:
CALL
简单搞定。
在上面的例子中,我们:
- 使用了“--”增加注释,以便理解复杂的存储过程;
- 添加了布尔值参数“有税”,如果要增加税则为真,否则为假;
- 通过DECLARE语句定义了两个局部变量;
- DECLARE要求指定变量名和数据类型,它也支持可选的默认值。
- 这个例子中的税率被默认设置为6%。
- 利用局部变量(总价)将SELECT语句的结果暂时存储;
- 借助IF语句检查有税是否为真。如果为真,则用另一SELECT语句增加营业税到局部变量total;
- 使用了SELECT语句将最终判断是否有税的总价保存到订单总价。
追溯其源
所谓天有不测风云,好好的工作说翻就翻(?),当我们接管了别人的数据库的时候,我们可能会需要知道那些存储过程当初是怎么被建立,由谁建立起来的。这种时候我们可以利用SHOW语句。
显示用来创建存储过程的CREATE语句:
SHOW
获得包括何时、由谁创建等详细信息的存储过程列表:
SHOW
为了限制返回的结果,可以用“LIKE”子句进行过滤:
SHOW
显示过程举例 让我们来查看一下方才的“计算总价”:
SHOW
以及其具体创建信息:
SHOW
也是很简单明了。
小结
今天讲解了储存过程、使用它的原因,创建它的方法(create procedure)和执行语句(call),智能储存过程,部分declare和if的用法,以及如何用show语句查看储存过程的相关信息。关于declare的用法,将在下一篇文章中更为详细地说明。
希望上文可以帮助大家对如何使用SQL中的储存过程有个初步的了解,如果还是有什么疑问或是建议的话,欢迎留言询问~
祝各位学习愉快!