MySQL基础笔记(六) 存储过程与函数
写在开头:本文所有的示例都是基于workers
表,表中保存了某公司的员工姓名、性别、工资、年龄和居住城市,如下:
+----+-----------+--------+--------+------+----------------+
| id | name | sex | salary | age | city |
+----+-----------+--------+--------+------+----------------+
| 2 | Paul | male | 5170 | 23 | Boston |
| 4 | Robin | male | 8350 | 40 | Beijing |
| 5 | Nina | female | 6700 | 27 | Chicago |
| 6 | Jacky | male | 9000 | 35 | Beijing |
| 7 | Tim | male | 5600 | 29 | Chicago |
| 8 | Katherine | female | 7000 | 32 | Washington D.C |
+----+-----------+--------+--------+------+----------------+
一、定义
存储程序可以分为存储过程和函数。
1.1 存储过程的定义
存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集。存储过程在数据库中经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。
1.2 函数的定义
存储函数(简称函数)在本质上与存储过程没有区别。
只是函数有如:只能返回一个变量的限制,而存储过程可以返回多个。函数是可以嵌入在SQL中使用,可以在select中调用,而存储过程不行。
二、创建存储过程和函数
存储过程和函数的创建过程很相似。
2.1 创建存储过程
创建存储过程使用CREATE PROCEDURE
语句:
CREATE PROCEDURE p_name(参数列表)
[characteristics...]
BEGIN
routine_body;
END;
begin和end语句用来限定存储过程体。参数列表可以为空,若不为空,则每个参数的形式如下:
[IN|OUT|INOUT] 参数名 参数类型
其中,IN表示输入参数,OUT表示输出参数,INOUT表示既可以输入也可以输出。
characteristics 是可选的参数,用于指定存储过程的特性:
language sql
:说明存储过程由SQL语句组成,目前SQL是language特性的唯一值。[not]deterministic
:表示结果是确定的,相同的输入会得到相同的输出;加not
表示结果不确定,相同的输入可能得到不同的输出。默认为 not deterministic。contains sql|no sql|reads sql data|modifies sql data
:
contains sql
:存储过程包含SQL语句,但不包含读写数据的语句。no sql
:存储过程不包含SQL语句。reads sql data
:存储过程包含读数据的语句。modifies sql data
:存储过程包含读写数据的语句。
sql security {definer|invoker}
:指明谁有权限执行存储过程。definer表示只有定义者才能执行,invoker表示拥有权限的调用者可以执行。默认为definer。comment'string'
:注释信息,可以用来描述存储过程或函数。
2.2 创建函数
创建函数使用CREATE FUNCTION
语句:
CREATE FUNCTION f_name(参数列表)
RETURNS type
[characteristics...]
routine_body
参数列表可以为空,若不为空,声明形式与存储过程的声明形式一样。characteristics用于指定函数的特性,取值同上,这里不再赘述。
RETURNS type
表示函数的返回类型;routine_body是函数体,函数体中必须包含一个 RETURN value 语句。
三、调用存储过程和函数
下面通过两个实例来说明存储过程、函数的创建和调用过程。
3.1 存储过程示例
创建一个存储过程,用来计算workers
表中每个员工的平均工资:
CREATE PROCEDURE getAverageSalary()
BEGIN
SELECT AVG(salary) FROM workers;
END;
实际的执行过程如下:
mysql> DELIMITER //
mysql> CREATE PROCEDURE getAverageSalary()
-> BEGIN
-> SELECT AVG(salary) FROM workers;
-> END//
Query OK, 0 rows affected (0.05 sec)
mysql> DELIMITER ;
DELIMITER //
语句的作用是将MySQL的结束符设置为//
,因为MySQL默认的语句结束符为;
,为了避免与存储过程中SQL语句结束符相冲突,需要使用 delimiter 改变存储过程的结束符,并以END//
结束存储过程。存储过程定义完毕之后再用DELIMITER ;
恢复默认结束符。当然也可以指定其他符号做为结束符。
下面我们调用一下 getAverageSalary() 存储过程,使用CALL
命令:
mysql> CALL getAverageSalary();
+-------------+
| AVG(salary) |
+-------------+
| 6970.0000 |
+-------------+
1 row in set (0.20 sec)
3.2 函数示例
同样的,我们创建一个函数来计算平均工资:
CREATE FUNCTION getAverageSalary()
RETURNS DECIMAL(8,4)
RETURN(SELECT AVG(salary) FROM workers);
实际的执行过程如下:
mysql> DELIMITER //
mysql> CREATE FUNCTION getAverageSalary()
-> RETURNS DECIMAL(8,4)
-> RETURN(
-> SELECT AVG(salary) FROM workers
-> )//
Query OK, 0 rows affected (0.11 sec)
mysql> DELIMITER ;
在MySQL中,自定义的函数与MySQL内部函数的使用方法是一样的,可以嵌入SQL中。我们用SELECT
调用:
mysql> SELECT getAverageSalary();
+--------------------+
| getAverageSalary() |
+--------------------+
| 6970.0000 |
+--------------------+
四、复杂的存储过程和函数
4.1 变量的使用
变量可以在子程序中声明并使用,这些变量的作用范围是在BEGIN...END
中。
4.1.1 定义变量
在存储过程中使用declare
语句定义变量:
DECLARE 变量名 变量类型 [DEFAULT val];
如果没有 DEFAULT 子句,初始值为NULL 。
4.1.2 为变量赋值
MySQL中使用SET
语句为变量赋值:
SET 变量名=表达式;
例如:
DECLARE var1, var2, var3 INT;
SET var1 = 10, var2 = 20;
SET var3 = var1 + var2;
另外还有一种给变量赋值的方法:
SELECT 字段1,字段2... INTO 变量1,变量2... FROM table_name WHERE condition
这个SELECT语法把选定的列直接存储到对应位置的变量中。
4.1.3 用户级变量
前面用DECLARE
定义的变量是局部变量,只能在BEGIN...END
之间起作用。而用户变量对于该连接的用户来说是全局的。
用户变量通常用@var_name
表示。用户变量与连接有关,一个客户端定义的变量不能被其它客户端看到或使用。当客户端退出时,该客户端连接的所有变量将自动释放。
创建用户变量不需要事先声明,直接SET赋值即可:
SET @var_name = expr [, @var_name = expr] ...
- 在SET语句中,可以使用
=
或:=
进行赋值。 - 在非SET语句中,只能使用
:=
进行赋值,因为=
被视为一个比较操作符。
4.2 流程控制的使用
MySQL中的流程控制语句有:IF
语句、CASE
语句、LOOP
语句、WHILE
语句、LEAVE
语句、ITERATE
语句和REPEAT
语句。
4.2.1 IF语句
语法格式如下:
IF expr_condition THEN statement_list
[ELSEIF expr_condition THEN statement_list]...
[ELSE statement_list]
END IF;
4.2.2 CASE语句
CASE语句有两种语法格式,第一种如下:
CASE expr
WHEN value1 THEN statement_list
WHEN value2 THEN statement_list
...
[ELSE statement_list]
END CASE;
第二种如下:
CASE
WHEN expr_condition1 THEN statement_list
WHEN expr_condition2 THEN statement_list
...
[ELSE statement_list]
END CASE;
注意:在存储程序里的 CASE 语句 与 直接在SELECT查询里使用的 CASE 函数有略微的不同。在存储程序里的 CASE 语句不能有ELSE NULL
子句,并且用END CASE
而不是END
来终止。
4.2.3 LOOP语句
LOOP语句的语法如下:
[loop_label:]LOOP
statement_list
END LOOP [loop_label]
loop_label是LOOP语句的标签,该参数可以省略。 LOOP 内的语句一直重复执行直到退出循环,退出循环使用LEAVE
语句。
4.2.4 LEAVE语句
LEAVE语句用来退出任何被标注的流程控制语句,语法如下:
LEAVE label;
4.2.5 ITERATE语句
ITERATE语句将执行顺序转到语句段开头处,ITERATE只可以出现在 LOOP、REPEAT和WHILE语句内。语法如下:
ITERATE label;
通俗点讲,就是相当于C++里的continue
。
4.2.6 REPEAT语句
REPEAT语句创建一个带条件判断的循环过程:
[repeat_label:]REPEAT
statement_list
UNTIL expr_condition
END REPEAT [repeat_label]
4.2.7 WHILE语句
WHILE语句也是创建一个带条件判断的循环过程,不同的是在每次执行循环体时先判断:
[while_label:]WHILE expr_condition DO
statement_list
END WHILE [while_label]
4.3 定义条件和处理程序
特定条件需要特定处理,定义条件是事先定义程序执行过程中遇到的问题,处理程序定义了在遇到这些问题时应当采取的处理方式,这样可以保证存储过程或函数在遇到警告或错误时能继续执行。
4.3.1 定义条件
定义条件也是使用DECLARE
语句:
DECLARE condition_name CONDITION FOR SQLSTATE 'sqlstate_value' | mysql_error_code;
sqlstate_value 和 mysql_error_code 都可以表示MySQL的错误,例如:ERROR 1064(42000)
中,sqlstate_value的值是42000,mysql_error_code的值是1064。
这个语句指定需要特殊处理的条件。它将一个名字和指定的错误条件关联起来,这个名字可以用在后面的处理程序中。例如:定义'ERROR 1064(42000)'
错误名称为syntax_error
。
DECLARE syntax_error CONDITION FOR SQLSTATE '42000'; /*方法一*/
DECLARE syntax_error CONDITION FOR 1064; /*方法二*/
4.3.2 定义处理程序
定义处理程序语法如下:
DECLARE handler_type HANDLER FOR condition_value sp_statement;
- handler_type:表示错误处理方式,只能取以下3个值。
CONTINUE
:遇到错误不处理,继续执行;EXIT
:遇到错误马上退出;UNDO
:遇到错误后撤回之前的操作,MySQL暂不支持。
- condition_value:表示错误类型,可以有以下值:
SQLSTATE 'sqlstate_value'
mysql_error_code
- condition_name:自定义的条件名称
SQLWARNING
:匹配所有以01开头的SQLSTATE错误代码NOT FOUND
:匹配所有以02开头的SQLSTATE错误代码SQLEXCEPTION
:匹配所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE错误代码
- sp_statement:程序语句段,表示在遇到定义的错误时,需要执行的存储过程或函数。
4.4 光标的使用
查询语句可能返回多条记录,如果数据量非常大,需要使用光标(cursor)来逐条读取查询结果集中的记录。
4.4.1 声明光标
光标必须在打开之前被声明,并且其中用到的变量或条件必须在声明光标之前被声明。MySQL中使用DECLARE
关键字来声明光标:
DECLARE cursor_name CURSOR FOR select_statement;
其中的 SELECT 语句返回一个用于创建光标的结果集。
4.4.2 打开光标
打开光标的语法如下:
OPEN cursor_name;
4.4.3 使用光标
通过FETCH
关键字从光标中逐条读取到变量中:
FETCH cursor_name INTO var_name[,...];
变量var_name必须在声明光标之前就定义好。
4.4.4 关闭光标
关闭光标的语法如下:
CLOSE cursor_name;
**注意:**MySQL中光标只能在存储过程和函数中使用。
4.4.5 示例
在workers
表的基础上,创建一个存储过程,根据输入的城市名,输出该城市所有员工的名字。
mysql> DELIMITER //
mysql> CREATE PROCEDURE useCursorDemo(IN city_name VARCHAR(15))
-> BEGIN
-> DECLARE m_name VARCHAR(10);
-> DECLARE m_city VARCHAR(15);
-> DECLARE m_stop INT DEFAULT 0;
-> DECLARE mycursor CURSOR FOR SELECT name,city FROM workers WHERE city=city_name;
-> DECLARE CONTINUE HANDLER FOR NOT FOUND SET m_stop=1;
-> OPEN mycursor;
-> FETCH mycursor INTO m_name,m_city;
-> WHILE m_stop!=1 DO
-> SELECT m_name,m_city;
-> FETCH mycursor INTO m_name,m_city;
-> END WHILE;
-> CLOSE mycursor;
-> END//
Query OK, 0 rows affected (0.08 sec)
mysql> DELIMITER ;
调用useCursorDemo
存储过程:
mysql> CALL useCursorDemo('Chicago');
+--------+---------+
| m_name | m_city |
+--------+---------+
| Nina | Chicago |
+--------+---------+
1 row in set (0.05 sec)
+--------+---------+
| m_name | m_city |
+--------+---------+
| Tim | Chicago |
+--------+---------+
1 row in set (0.05 sec)
通过这个例子,我们可以了解到如何在存储过程或函数中使用变量、光标和流程控制。
五、修改、删除存储过程和函数
使用ALTER
语句可以修改存储过程或函数的特性,语法如下:
ALTER {PROCEDURE|FUNCTION} sp_name [characteristic]
sp_name是存储过程或函数的名称,characteristic指定存储过程或函数的特性,与创建过程的参数取值是一样的。
使用DROP
语句删除存储过程或函数,语法如下:
DROP {PROCEDURE|FUNCTION} [IF EXISTS] sp_name;
附:MySQL存储过程和函数有什么区别?
在本质上它们都是存储程序。
- 函数只能通过 return 语句返回单个值或表对象;而存储过程不允许执行 return,但可以通过 OUT 参数返回多个值。
- 函数限制比较多,不能用临时表,只能用表变量,还有一些函数都不可用等等;而存储过程的限制相对就比较少。
- 函数可以嵌入在SQL语句中使用,可以在SELECT语句中作为查询语句的一个部分调用;而存储过程一般是作为一个独立的部分来执行。
MySQL基础笔记(六) 存储过程与函数的更多相关文章
- MYSQL基础笔记(六)- 数据类型一
数据类型(列类型) 所谓数据烈性,就是对数据进行统一的分类.从系统角度出发时为了能够使用统一的方式进行管理,更好的利用有限的空间. SQL中讲数据类型分成三大类:1.数值类型,2.字符串类型和时间日期 ...
- MYSQL基础笔记(五)- 练习作业:站点统计练习
作业:站点统计 1.将用户的访问信息记录到文件中,独占一行,记录IP地址 <?php //站点统计 header('Content-type:text/html;charset=utf-8'); ...
- MYSQL基础笔记(四)-数据基本操作
数据操作 新增数据:两种方案. 1.方案一,给全表字段插入数据,不需要指定字段列表,要求数据的值出现的顺序必须与表中设计的字段出现的顺序一致.凡是非数值数据,到需要使用引号(建议使用单引号)包裹. i ...
- MYSQL基础笔记(三)-表操作基础
数据表的操作 表与字段是密不可分的. 新增数据表 Create table [if not exists] 表名( 字段名 数据类型, 字段名 数据类型, 字段n 数据类型 --最后一行不需要加逗号 ...
- MYSQL基础笔记(二)-SQL基本操作
SQL基本操作 基本操作:CRUD,增删改查 将SQL的基本操作根据操作对象进行分类: 1.库操作 2.表操作 3.数据操作 库操作: 对数据库的增删改查 新增数据库: 基本语法: Create da ...
- MYSQL基础笔记(一)
关系型数据库概念: 1.什么是关系型数据库? 关系型数据库:是一种建立在关系模型(数学模型)上的数据库 关系模型:一种所谓建立在关系上的模型. 关系模型包含三个方面: 1.数据结构:数据存储的问题,二 ...
- MySql(三)存储过程和函数
MySql(三)存储过程和函数 一.什么是存储过程和函数 二.存储过程和函数的相关操作 一.什么是存储过程和函数 存储过程和函数是事先经过编译并存储在数据库中的一段SQL语句的集合,调用存储过程和函数 ...
- mysql 开发基础系列17 存储过程和函数(上)
一. 概述 存储过程和函数是事先经过编译并存储在数据库中的一段sql语句集合,可以简化应用开发人员的很多工作,减少数据在数据库与应用服务器之间的传输,提高数据处理效率是有好处的.存储过程和函数的区别在 ...
- mysql 开发基础系列18 存储过程和函数(下)
1. 光标的使用(游标) 在存储过程和函数中可以使用光标对结果集进行循环的处理,光标使用包括光标的声明,open ,fetch,close. 下面在存储过程中使用一个光标, 这个举例中光标里的逻辑不重 ...
随机推荐
- 第1节 flume:6、flume的入门测试案例
案例:使用网络telent命令向一台机器发送一些网络数据,然后通过flume采集网络端口数据. 1.2.1 Flume的安装部署 第一步:下载解压修改配置文件 Flume的安装非常简单,只需要解压即可 ...
- 错误的语法:"create view必须是批处理中仅有的语句"
编写脚本提示: 错误的语法:"create view必须是批处理中仅有的语句" FROM sys.views WHERE name = 'v_CS_UserRoleNames' ) ...
- VR技术在数据中心3D机房中的应用(上)
VR技术在数据中心3D机房中的应用(上) 前两天跟朋友A吃饭,吃着吃着就说到了VR.近几年来,VR技术越来越火,感觉能跟VR沾点边的都特别高大上,朋友A也是,一提到VR,就怎么都掩盖不住他发自肺腑 ...
- Java 垃圾回收机制 (分代垃圾回收ZGC)
什么是自动垃圾回收? 自动垃圾回收是一种在堆内存中找出哪些对象在被使用,还有哪些对象没被使用,并且将后者删掉的机制.所谓使用中的对象(已引用对象),指的是程序中有指针指向的对象:而未使用中的对象(未引 ...
- 记录一个scrapy的坑
在win10上用命令 pip install scrapy 安装scrapy的时候提示: Could not find a version that satisfies the requirement ...
- 牛客网练习赛25 C 再编号
链接:https://www.nowcoder.com/acm/contest/158/C来源:牛客网 定义对 a 的再编号为 a' ,满足 . 现在有 m 次询问,每次给定 x,t ,表示询问经过 ...
- bzoj3336 Uva10572 Black and White
题目描述: 数据范围:2<=n,m<=8 题解: 很明显需要状压.但是怎么压不知道,压什么不知道. 然后从条件下手. 条件1要求黑色在一起白色在一起,记录轮廓线很容易做到. 条件2要求不能 ...
- js|jquery常用代码
页面重定位: window.location.replace("http://www.bczs.net"); window.location.href = "http:/ ...
- C语言之static用法
1,static修饰全局变量 限定变量的作用域.被static修饰的全局变量存储域不变,依然存储在静态存储区,即bss段或data段.但作用域发生改变,被static修饰全局变量只能被本文件的函数访问 ...
- Chrome浏览器 v68.0.3440.106 正式版怎么样?
谷歌浏览器Google Chrome稳定版迎来v68正式版第三个维护版本发布,详细版本号为v68.0.3440.106,上一个正式版v68.0.3440.84发布于8月1日,时隔8天Google又发布 ...