存储过程和函数是事先经过编译并存储在数据库中的一段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. suse下修改主机名

    export HOSTNAME=主机名 echo $HOSTNAME>/etc/HOSTNAME /etc/rc.d/boot.localnet stop /etc/rc.d/boot.loca ...

  2. Windows激活客户端 已停止工作

    win+r 进入运行 slmgr /ipx 新的sn slmgr /ato

  3. verilog 有符号数运算

    1)之前的笔记写过<补码探讨>,可知在FPGA综合成电路的时候最底层都是以补码的形式在运算,正数的补码就是本身,负数的补码要取反+1. (2)那么Verilog中编程的时候对编程人员来说, ...

  4. Linux-程序包管理

    Linux上的软件安装有2种形式:源码.二进制文件,源码需要在编译环境下编译安装,二进制可以直接安装. 1.程序包管理器 rpm 程序包管理器能够将目标二进制格式(也就是从源码编译好的二进制文件,包括 ...

  5. 下载 rpm 源码包并重新编译

    $ yumdownloader --source gdb $ rpmbuild --rebuild gdb-7.8.1-30.fc21.src.rpm $ cd ~/rpmbuild/SPECS/ $ ...

  6. ES6-字符串扩展-padStart(),padEnd()

    ES6 引入了字符串补全长度的功能,如果某个字符串不够指定长度,会在头部活尾部补全. padStart() 用于头部补全: padEnd() 用于尾部补全. 上面代码中,padStart 和 padE ...

  7. VMware Tools安装教程

    安装依赖: sudo yum install eject 步骤: 确保 Linux 虚拟机已打开电源. 如果正在运行 GUI 界面,请打开命令 shell. 注意:以 root 用户身份登录,或使用 ...

  8. 《http权威指南》读书笔记3

    概述 最近对http很感兴趣,于是开始看<http权威指南>.别人都说这本书有点老了,而且内容太多.我个人觉得这本书写的太好了,非常长知识,让你知道关于http的很多概念,不仅告诉你怎么做 ...

  9. react写一个todo

    概述 最近学习redux,打算先复习一下react,所以用react写了一个todo.记录下来,供以后开发时参考,相信对其他人也有用. 代码 代码请见我的github 组织架构如下图:

  10. [CocoaPods]入门

    什么是CocoaPods? CocoaPods管理Xcode项目的库依赖项. 项目的依赖项在名为Podfile的单个文本文件中指定.CocoaPods将解析库之间的依赖关系,获取生成的源代码,然后在X ...