存储过程和函数是事先经过编译并存储在数据库中的一段SQL语句的集合,存储和和函数的区别在于函数必须有返回值,而存储过程没有,存储过程的参数可以使用IN、OUT、INOUT类型,而函数的参数只能是IN类型。存储过程再简单点来说,就是为以后的使用而保存的一条或多条MySQL语句的集合。可将其视为批件,虽然它们的作用不仅限于批处理。在我看来, 存储过程就是有业务逻辑和流程的集合, 可以在存储过程中创建表,更新数据, 删除等等。本次博客就来讲一下存储过程

存储过程的操作

语法如下:

创建:
CREATE PROCEDURE sp_name([proc_parameter[,...]])
[characteristic...] routine_body proc_parameter:
[IN|OUT|INOUT] param_name type #type: Any valid MySQL data type
characteristic:
LANGUAGE SQL
|[NOT] DETERMINISTIC|{CONTAINS SQL|NO SQL|READS SQL DATA|MODIFIES SQL DATA}|SQL SECURITY {DEFINAER|INVOKER}|COMMENT 'string'
routine_body:
Valid SQL procedure statement or statements 修改:
ALTER PROCEDURE sp_name [characteristic...]
characteristic:
{CONTAINS SQL|NO SQL|READS SQL DATA|MODIFIES SQL DATA}|SQL SECURITY {DEFINAER|INVOKER}|COMMENT 'string' 调用:
CALL sp_name([parameter[,...]]) 删除:
DROP PROCEDURE sp_name 查看:
show PROCEDURE STATUS [like 'pattern']
SHOW CREATE PROCEDURE sp_name

MySQL的存储过程和函数中允许包含DDL语句,也允许在存储过程中执行提交或者回滚,但是存储过程和函数不允许执行LOAD DATA INFILE语句,存储过程和函数可以调用其他的过程或者函数。

插入小知识点@:

.用户变量:以"@"开始,形式为"@变量名"
用户变量跟mysql客户端是绑定的,设置的变量,只对当前用户使用的客户端生效。
.全局变量:定义方式 set GLOBAL 变量名 或者 set @@global.变量名
对所有客户端生效,只有具有super权限才可以设置全局变量。

存储过程简单来说,就是为以后的使用而保存的一条或多条MySQL语句的集合。可将其视为批件,虽然它们的作用不仅限于批处理。

在我看来, 存储过程就是有业务逻辑和流程的集合, 可以在存储过程中创建表,更新数据, 删除等等。

为什么要使用存储过程

  1. 通过把处理封装在容易使用的单元中,简化复杂的操作(正如前面例子所述)。
  2. 由于不要求反复建立一系列处理步骤,这保证了数据的完整性。如果所有开发人员和应用程序都使用同一(试验和测试)存储过程,则所使用的代码都是相同的。这一点的延伸就是防止错误。需要执行的步骤越多,出错的可能性就越大。防止错误保证了数据的一致性。
  3. 简化对变动的管理。如果表名、列名或业务逻辑(或别的内容)有变化,只需要更改存储过程的代码。使用它的人员甚至不需要知道这些变化。

users表如下:

创建存储过程,传入性别(男或女),显示对应性别的用户id,返回对应性别的人数(我的是在mysql front中操作):

#DELIMITER $$
CREATE PROCEDURE user_procedure(IN sex VARCHAR(2) character set utf8,OUT num INT)
BEGIN
SELECT id FROM users WHERE gender=sex;
SELECT FOUND_ROWS() INTO num;
END #$$
#DELIMITER ;

如果大家用的navicat版本,应该改成是:

DELIMITER $$
CREATE PROCEDURE user_procedure(IN sex VARCHAR(2) character set utf8,OUT num INT)
BEGIN
SELECT id FROM users WHERE gender=sex;
SELECT FOUND_ROWS() INTO num;
END $$
DELIMITER ;

上面记得中文字符字段,一定要设置编码:character set utf8,这里自己被坑了好久才觉悟过来...

调用

CALL user_procedure('女',@num);
select @num;

定义条件和处理

条件的定义和处理可以用来定义在处理过程中遇到问题时相应的处理步骤。

语法如下:

条件定义:
DECLARE condition_name CONDITION FOR condition_value condition_value:
SQLSTATE [VALUE] sqlstate_value
|mysql_error_code
条件处理:
DECLARE handler_type HANDLER FOR condition_value[,...] sp_statement handler_type:
CONTINUE|EXIT|UNDO condition_value:
SQLSTATE [VALUE] sqlstate_value
|condition_name|SQLWARNING|NOT FOUND|SQLEXCEPTION|mysql_error_code

继续用users表举个例子吧!
现在有数据如下:

(1)当没有进行条件处理的时候:

#delimiter $$
create procedure user_insert()
begin
set @x=1;
insert into users(id,gender,name) values(1,'男','常贵');
set @x=2;
insert into users(gender,name) values('女','大脚');
set @x=3;
END #$$

上面的例子可以看出,当插入id=1,主键重复了,直接退出了,并没有执行余下的语句,所以@x的值为1。

(2)可以对主键重复进行处理:

#delimiter $$
create procedure user_insert2()
begin
declare continue handler for sqlstate '' set @x2=1;
set @x=1;
insert into users(id,gender,name) values(3,'男','jack');
set @x=2;
insert into users(id,gender,name) values(1,'男','mary');
set @x=3;
end #$$
#delimiter ;

调用call user_insert2();

这次在调用存储过程的时候,并没有报错,而是在遇到主键重复的时候,会安装定义的continue去执行,所以继续向下执行。

condition_value的值可以是通过declare定义的condition_name,可以是SQLSTATE的值或者mysql_error_code的值会在是SQLWARNING、NOT FOUND、SQLEXCEPTION,这个3个值是3种定义好的错误类别,分别代表不同的含义:

SQLWARNING:是对所有以01开头的SQLSTATE代码的速记

NOT FOUND是对所有以02开头的SQLSTATE代码的速记

SQLEXCEPTION是对所有没有被SQLWARNING或者NOT FOUND捕获的SQLSTATE代码的速记。

以上的declare continue handler for sqlstate '23000' set @x2=1;也可以用以下几种方式来写:

#捕获mysql-error-code
declare continue handler for 1062 set @x2=1;
#事先定义condition_name
declare duplicatekey condition for sqlstate '23000';
declare continue handler for duplicatekey set @x2=1;
#捕获sqlexception
declare continue handler for sqlexception set @x2=1;

流程控制

mysql支持的流程控制有:IF、CASE、LOOP、LEAVE、ITERATE、REPEAT和WHILE语句。

1.IF

语法如下:

IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list]...
[ELSE statement_list]
END IF

举例:求两个数的最大值

#DELIMITER $$
CREATE PROCEDURE compare(IN n1 INT,IN n2 INT)
BEGIN
SET @res=0;
IF n1 > n2 THEN
SET @res=n1;
ELSEIF n1 = n2 THEN
SET @res=n1;
ELSE
SET @res=n2;
END IF;
END #$$
#DELIMITER ;

调用后查询结果如下:

2.CASE语句

语法如下:

CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list]...
[ELSE statement_list]
END CASE
或者:
CASE
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list]...
[ELSE statement_list]
END CASE

我们将以上例子使用case来实现:

#DELIMITER $$
CREATE PROCEDURE compare2(IN n1 INT,IN n2 INT)
BEGIN
SET @res=0;
CASE
WHEN n1>n2 THEN
SET @res=n1;
WHEN n1=n2 THEN
SET @res=n1;
ELSE
SET @res=n2;
END CASE;
END #$$
#DELIMITER ;

测试:

3.LOOP和LEAVE语句

LOOP可以实现简单的循环,通常和LEAVE一起使用,LOOP语法如下:

[begin_label:]LOOP
statement_list
END LOOP[end_label]

我们还是以users表为例,当前users表按照 id desc 数据如下:

使用循环向里面插入100行数据:

#DELIMITER $$
CREATE PROCEDURE userinset()
BEGIN
SET @x=0;
ins: LOOP #标签为ins
SET @x=@x+1;
IF @x=100 THEN
LEAVE ins; #当@x=100的时候,则退出循环
END IF;
INSERT INTO users(name,gender) values('周伯通', '男');
END LOOP ins;
END #$$
#DELIMITER ;

测试:

call userinset();
select count(1) from users;

4.ITERATE语句

必须在循环中使用,作用是跳过当前循环的剩下的语句,直接进入下一轮循环,相当于一些高级语言中的continue。

只向表中插入奇数行:(仍以users为例):

#delimiter $$
CREATE PROCEDURE inserinfo()
BEGIN
set @x=1000103;
ins: LOOP
SET @x=@x+1;
IF @x=1000113 THEN
LEAVE ins;
ELSEIF mod(@x,2)=0 THEN
ITERATE ins;
END IF;
INSERT INTO users(id,name) VALUES(@x,'乔峰');
END LOOP ins;
END #$$
#delimiter ;

测试:call inserinfo();

5.REPEAT语句

有条件的循环控制语句,当满足条件的时候退出循环,语法如下:

[begin_label:]REPEAT
statement_list
UNTIL search_condition
END REPEAT [end_label]

举例:再在上面例子中插入10行:

#delimiter $$
CREATE PROCEDURE inserinfo2()
BEGIN
DECLARE x INT DEFAULT 9;
ins: REPEAT
SET x=x+1;
INSERT INTO users(name,gender) VALUES(x,'保密');
UNTIL x>18 END REPEAT; END #$$
#delimiter ;

调用:call inserinfo2();查看数据如下

6.WHILE语句
WHILE是满足条件才执行。
语法如下:

[begin_lable:]WHILE search_condition DO
statement_list
END WHILE [end_label]

以上的例子如果用while来实现如下:

#delimiter $$
CREATE PROCEDURE inserinfo3()
BEGIN
DECLARE x INT DEFAULT 9;
ins: WHILE x<=18 DO
SET x=x+1;
INSERT INTO users(name,gender) VALUES(x,'女');
END WHILE;
END #$$
#delimiter ;

测试:call inserinfo3();

光标的使用

在存储过程和函数中,可以使用光标对结果进行循环的处理,语法如下:

声明光标:
DECLARE cursor_name CURSOR FOR select_statement
OPEN光标:
OPEN cursor_name
FETCH光标:
FETCH cursor_name INTO var_name[,var_name]...
CLOSE光标:
CLOSE cursor_name

举例:

还是以users表为例,好吧。夜深人静。。不早了,未完待续....

Mysql 存储过程实例详解的更多相关文章

  1. 9.SQL存储过程实例详解

    本文用3个题目,从建立数据库到创建存储过程,详细讲解数据库的功能. 题目1 学校图书馆借书信息管理系统建立三个表:学生信息表:student 字段名称 数据类型 说明 stuID char(10) 学 ...

  2. SQL存储过程实例详解

    本文用3个题目,从建立数据库到创建存储过程,详细讲解数据库的功能. 题目1         学校图书馆借书信息管理系统建立三个表:         学生信息表:student 字段名称 数据类型 说明 ...

  3. mysql触发器trigger 实例详解

    mysql触发器trigger 实例详解 (转自 https://www.cnblogs.com/phpper/p/7587031.html)   MySQL好像从5.0.2版本就开始支持触发器的功能 ...

  4. mysql数据库分区功能及实例详解

    分区听起来怎么感觉是硬盘呀,对没错除了硬盘可以分区数据库现在也支持分区了,分区可以解决大数据量的处理问题,下面一起来看一个mysql数据库分区功能及实例详解   一,什么是数据库分区 前段时间写过一篇 ...

  5. MySQL数据库备份详解

    原文:MySQL数据库备份详解 对于任何数据库来说,备份都是非常重要的 数据库复制不能取代备份的作用 比如我们由于误操作,在主数据库上删除了一些数据,由于主从复制的时间很短,在发现时,从数据库上的数据 ...

  6. linux基础-磁盘阵列(RAID)实例详解

    磁盘阵列(RAID)实例详解 raid技术分类 软raid技术 硬raid技术 Raid和lvm的区别 为什么选择用raid RAID详解 RAID-0 RAID-1 RAID-5 Raid-10 R ...

  7. MySQL关闭过程详解和安全关闭MySQL的方法

    MySQL关闭过程详解和安全关闭MySQL的方法 www.hongkevip.com 时间: -- : 阅读: 整理: 红客VIP 分享到: 红客VIP(http://www.hongkevip.co ...

  8. 转:【工欲善其事必先利其器】—Entity Framework实例详解

    开始本篇文章之前,先说一下Entity Framework 6 Alpha1在NuGet中已可用,原文链接http://blogs.msdn.com/b/adonet/archive/2012/10/ ...

  9. Mysql加锁过程详解(5)-innodb 多版本并发控制原理详解

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

随机推荐

  1. linux 系统管理学习

    Linux系统管理一.进程管理1.进程管理的作用1)判断服务器健康状态2)查看系统中所有进程3)杀死进程2.进程的查看1)查看所有进程ps aux 查看系统中所有进程ps -le 查看系统中所有进程- ...

  2. python模块:xml.dom.minidom

    """Simple implementation of the Level 1 DOM. Namespaces and other minor Level 2 featu ...

  3. hive 语法 case when 语法

    ' then '精选' else null end as sale_type 注意: end不能少

  4. 统计C/C++代码行数

    近日在写一个统计项目中C/C++文件(后缀名:C/CPP/CC/H/HPP文件)代码行数的小程序.给定包含C/C++代码的目录,统计目录里所有C/C++文件的总代码行数.有效代码行数.注释行数.空白行 ...

  5. 在 Linux 上如何挂载 qcow2 磁盘镜像

    1.下载qemu-nbd工具 sudo apt-get install qemu-utils 或者 sudo yum install qemu-img 2.加载nbd模块,然后挂载 sudo modp ...

  6. JS跨域调用之document.domain--相同基础域名页面之间的调用

    利用document.domain 实现跨域: 前提条件:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域 Javascript出于对 ...

  7. javascript知识整理之this

    js中的this是一个头疼的问题,尤其对于笔者这种初级的菜鸟来讲,下面梳理下this的知识,可以当做是初级进阶也好入门也罢,总归输出的才是自己掌握的: Js中this不是由词法作用域决定的 而是调用时 ...

  8. 9:集合collection

    第一 集合框架的概述 集合类的由来:  对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定,就使用集合容器进行存储.   集合和数组的区别: 数组虽然可以存储对象,但是长度是固定的:集合长度 ...

  9. 功能强大的swiper插件

    概述 今天体验了一下swiper,真是太强大了,无论是PC端还是移动端,各种轮播滑块效果随便实现.美中不足的是,有些实现需要自己想办法.下面我记录下我的需求和我的实现,供以后开发时参考,相信对其他人也 ...

  10. js中的类

    概述 经典的老书害人啊,全是讨论怎么解决javascript里面用函数形式定义类的坑.结果es2015直接用class关键字解决了所有问题.虽然class关键字没有什么新东西,只是js现有继承结构的语 ...