天天看点

call 存储过程时必须声明表示符_SQL之打CALL储存

call 存储过程时必须声明表示符_SQL之打CALL储存

给SQL打个CALL~

各位好久不见~【突然出现!

call 存储过程时必须声明表示符_SQL之打CALL储存

可能大家以为我这几天在偷懒,但其实···

我只是在沉迷zsh而已。【正色

上次macOS系统从bash更新至zsh之后我果然忘记把里面配置一起更新了~

call 存储过程时必须声明表示符_SQL之打CALL储存

今天要讲一个相对复杂但非常好用然而学校并没有正式教授的东西。

存储过程。

而它彻底依赖线上编译似乎有些困难,目前我借助了Terminal进行本地的MySQL编写。#论发现自己配置没更新的正确起因

作为一个完美主义者(不是),我满心希望在Terminal写出来的东西是这样的效果:

call 存储过程时必须声明表示符_SQL之打CALL储存

或者至少是这样的:

call 存储过程时必须声明表示符_SQL之打CALL储存

然而···

call 存储过程时必须声明表示符_SQL之打CALL储存

它是这样的···

call 存储过程时必须声明表示符_SQL之打CALL储存

研究了两三天竟然毫无头绪呢。

call 存储过程时必须声明表示符_SQL之打CALL储存

不过至少它能用,嗯。

打CALL的理由

在我们讲解视图的时候便可以注意到,SQL的语句有些时候会变得非常繁琐。比如当我们处理订单的时候,我们实际上需要

  1. 确认库存是否足够;
  2. 减少库存以正确反映接受预定后的数量;
  3. 建立发货单;
  4. 联系顾客提供运送信息;
  5. 若是库存短缺,则要找到供应商补货
  6. ……

如果接到订单的每一次我们都需要重复以上的编码,这工作也过于单调且无趣了。

若是我们可以

把流程分门别类地建立起一个“模版”

,这不但会大幅便捷我们的操作,统一我们的代码以

保证数据的一致性

,还可以

简化对变动的管理

简单、安全、高性能,简直完美~

这就是储存过程。

那么我们应该如何使用它呢?

打个CALL

首先要提到一点的是,

储存过程比一般的基本语句要难,使用它时会要求有更高的经验以及技能

因此,若是一时没能理解或是顺利地对其进行编写也不必灰心丧气,毕竟不管什么事情都需要积累。【突然开始安慰自己

call 存储过程时必须声明表示符_SQL之打CALL储存
MySQL称存储过程的执行为调用

,因此MySQL执行存储过程的语句为CALL。CALL接受存储过程的名字以及需要传递给它的任意参数:

CALL 
           

存储过程可以显示结果,也可以不显示结果。

创建存储过程也遵循了SQL语句一贯的“简单粗暴”,即为create(创建)procedure(过程):

CREATE 
           

如果存储过程接受参数,它们将在( )中列举出来;若是存储过程没有参数,后跟的( )仍然需要。

这里需要注意的是两个分号“;”(储存内容以及END)。

默认的MySQL语句分隔符为分号“;”。如果命令行实用程序要解释存储过程自身内的“;”字符,则它们最终不会成为存储过程的成分,这会使存储过程中的SQL出现句法错误。

解决办法是临时

更改命令行实用程序的语句分隔符

DELIMITER 
           

这样,存储过程体内的“;”无需变动,并且可以正确地传递给数据库引擎。

除“”符号外,任何字符都可以用作语句分隔符。

删除储存内容的方法也很简单,如同删除表格一般使用DROP语句即可:

DROP 
           
创建储存内容举例

假如我们想一口气知道产品的平均价,最低价以及最高价,我们可以先将其创建(CREATE)储存内容(PROCEDURE):

DELIMITER 
           

然后对其调取(CALL):

CALL 
           
call 存储过程时必须声明表示符_SQL之打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 @最低价;

call 存储过程时必须声明表示符_SQL之打CALL储存

我们当然也可以把三个一口气都列出来:

SELECT 
           
call 存储过程时必须声明表示符_SQL之打CALL储存

干净整齐。

省心智能化

现在大家可能都会有些疑惑:

  • 没觉得这样折腾会方便多少啊?
  • 可能还是直接用SELECT语句更快?
  • 将那些原本简单的SELECT语句封装起来,不是反而使简单的事情复杂化了?
call 存储过程时必须声明表示符_SQL之打CALL储存

是的没错,其实那些小打小闹对于储存过程来说,颇有些“杀鸡焉用牛刀”之感。

只有在存储过程内包含业务规则和智能处理时,它的威力才可以真正显现出来。

假如我们想要知道一笔订单的总价,并且需要根据实际情况来增加营业税,那么我们应该怎么做?

按照过去的经验,若是我们单纯想要知道订单合计:

SELECT 
           

如果要增加营业税的的话,只需在总价的基础上加工即可:

SELECT 
           

思路不难,操作···似乎也不是很困难。

智能存储过程举例

但如果有一个模版可以让我们更轻松地应付该工作,那会是什么样的?

输入我们想要计算的订单号,以及该订单是否需要打税,然后SQL自动返回该订单的总计。

DELIMITER 
           

假如我们想知道订单号为20005且需要交税的订单总价:

CALL 
           
call 存储过程时必须声明表示符_SQL之打CALL储存

假如我们想知道订单号为20005但不需要交税的订单总价:

CALL 
           
call 存储过程时必须声明表示符_SQL之打CALL储存

简单搞定。

在上面的例子中,我们:

  • 使用了“--”增加注释,以便理解复杂的存储过程;
  • 添加了布尔值参数“有税”,如果要增加税则为真,否则为假;
  • 通过DECLARE语句定义了两个局部变量;
  • DECLARE要求指定变量名和数据类型,它也支持可选的默认值。
  • 这个例子中的税率被默认设置为6%。
  • 利用局部变量(总价)将SELECT语句的结果暂时存储;
  • 借助IF语句检查有税是否为真。如果为真,则用另一SELECT语句增加营业税到局部变量total;
  • 使用了SELECT语句将最终判断是否有税的总价保存到订单总价。

追溯其源

所谓天有不测风云,好好的工作说翻就翻(?),当我们接管了别人的数据库的时候,我们可能会需要知道那些存储过程当初是怎么被建立,由谁建立起来的。这种时候我们可以利用SHOW语句。

显示用来创建存储过程的CREATE语句:

SHOW 
           

获得包括何时、由谁创建等详细信息的存储过程列表:

SHOW 
           

为了限制返回的结果,可以用“LIKE”子句进行过滤:

SHOW 
           
显示过程举例

让我们来查看一下方才的“计算总价”:

SHOW 
           
call 存储过程时必须声明表示符_SQL之打CALL储存

以及其具体创建信息:

SHOW 
           
call 存储过程时必须声明表示符_SQL之打CALL储存

也是很简单明了。

小结

今天讲解了储存过程、使用它的原因,创建它的方法(create procedure)和执行语句(call),智能储存过程,部分declare和if的用法,以及如何用show语句查看储存过程的相关信息。关于declare的用法,将在下一篇文章中更为详细地说明。

希望上文可以帮助大家对如何使用SQL中的储存过程有个初步的了解,如果还是有什么疑问或是建议的话,欢迎留言询问~

祝各位学习愉快!