存储过程和函数
存储过程和函数是事先经过编译并存储在数据库中的一段SQL语句的集合.
调用存储过程和函数可以简化应用开发人员的工作,减少数据在数据库和应用服务器之间的传输,提高数据处理的效率.
存储过程和函数的区别在于:
函数必须有返回值,而存储过程没有.
存储过程的参数可以使用 IN,OUT,INOUT 类型;而函数的参数只能是IN类型.
如果有函数从其他类型数据库迁移到MySQL就可能需要把函数改造成存储过程.
存储过程和函数的相关操作
首先确认是否有相应的权限.
创建存储过程/函数 需要CREATE ROUTINE权限.
修改/删除 存储过程/函数 需要ALTER ROUTINE权限.
执行存储过程/函数 需要EXECUTE权限.
1).创建/修改 存储过程或函数
CREATE PROCEDURE sp_name ([proc_param[,...]])
[characteristic …]
routine_body
CREATE FUNCTION sp_name ([func_param[,...])
RETURNS type
[characteristic …]
routine_body
其中,
proc_param :
[IN|OUT|INOUT] param_name type
func_param :
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 {DEFINER | INVOKER}
| COMMENT 'string'
routine_body :
valid SQL procedure statement or statements .
ALTER {PROCEDURE | FUNCTION} sp_name [characteristic ...]
characteristic :
{CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}
|SQL SECURITY {DEFINER|INVOKER}
|COMMENT 'string'
调用存储过程/函数,使用关键字CALL :
CALL sp_name ([[parameter [,...]])
注意: 存储过程/函数 中允许包含DDL ,也可以在存储过程中执行COMMIT/ROLLBACK 操作,还可以调用其他的过程/函数;
但是存储过程/函数 中不允许使用 LOAD DATA INFILE 语句.
Demo :
DELIMITER $$
CREATE PROCEDURE film_in_stock (IN p_film_id INT , IN p_store_id INT , OUT p_film_count INT)
READS SQL DATA
BEGIN
SELECT inventory_id
FROM inventory
WHERE film_id = p_film_id
AND store_id = p_store_id
AND inventory_in_stock(inventory_id);
SELECT FOUND_ROWS() INTO p_film_count;
END $$
DELIMITER ;
CALL film_in_stock(2,2,@a);
SELECT @a ;
注意 : 与视图的创建语法不同,存储过程/函数 的CREATE语法不支持使用 CREATE OR REPLACE对存储过程/函数进行修改.如需修改,可以执行ALTER语法.
characteristic特征值的简单说明:
1).LANGUAGE SQL
说明下面过程的BODY是使用SQL语句编写(系统默认的),以后MySQL可能支持其它语言.
2).[NOT] DETERMINISTIC:
目前还未被优化程序使用
DETERMINISTIC 每次输入一样输出也一样的程序
NOT DETERMINISTIC(系统默认).
3).{CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}
目前这些特征值只是提供给服务器,并未用来约束存储过程实际使用数据的情况.
CONTAINS SQL 表示子程序不包含读或者写数据的语句
NO SQL 表示子程序不包含SQL语句
READS SQL DATA 表示子程序包含读数据的语句
MODIFIES SQL DATA 表示子程序包含写数据的语句
默认值是 CONTAINS SQL
4).SQL SECURITY {DEFINER | INVOKER}
指定子程序 该用创建子程序者的权限来执行,还是使用调用者的权限来执行.默认值是DEFINER , 即使用创建者的权限执行.
5).COMMENT 'string'
存储过程/函数 的注释信息.
2.删除存储过程/函数
一次性只能删除一个存储过程/函数.需要有ALTER ROUTINE 权限.
DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name
3.查看存储过程/函数
1).查看存储过程/函数 的状态
SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']
2).查看存储过程/函数 的定义
SHOW CREATE {PROCEDURE|FUNCTION} sp_name
3).通过查看information_schema.Routines 了解存储过程/函数 的信息
包含名称,类型,语法,创建人等信息.
demo:SELECT * FROM routines WHERE ROUTINE_NAME = 'film_in_stock' \G
4.变量的使用
1).变量的定义
DECLARE var_name [,...] type [DEFAULT value]
2).变量的赋值
SET var_name = expr [,var_name = expr] ...
其中,expr 可以是字面量,函数返回值,SELECT 语句(要求结果有且只有一行)等.
或者使用SELECT .. INTO .. 语句
SELECT col_name[,..] INTO var_name[,..] table_expr
Demo :
DECLARE $$
CREATE FUNCTION get_customer_balance( p_customer_id INT , p_effective_date DATETIME )
RETURNS DECIMAL(5,2)
DETERMINISTIC
READS SQL DATA
BEGIN
...
DECLARE v_payments DECIMAL(5,2) ;
...
SELECT IFNULL (SUM(payment,amount),0) INTO v_payments
FROM payment
WHERE payment.payment_date <= p_effective_date
AND payment.customer_id = p_customer_id ;
...
RETURN v_rentfees + v_overfees - v_payments ;
END $$
DECLARE ;
CALL get_customer_balance(1,'2018-03-02 09:11:15') ;
5.定义条件和处理
1).条件的定义
DECLARE condition_name CONDITION FOR condition_value
其中,condition_value :
SQLSTATE [VALUE] sqlstate_value | mysql_error_code
2).条件的处理
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
demo:todo
6.光标的使用 --就是游标
可以使用游标对结果集进行循环处理
1).声明光标
DECLARE cursor_name CURSOR FOR select_statement
select_statement 中的SELECT语句 不能包含 INTO , 即不可以是SELECT .. INTO ..语句
SELECT 语句查询出来的列数 , 必须与FETCH游标中的接收数据的变量数 一致.
2).OPEN光标
OPEN cursor_name
3).FETCH光标
FETCH cursor_name INTO var_name[,var_name,..]
4).CLOSE光标
CLOSE cursor_name
Demo : —— 需要注意 DECLARE 声明的顺序 : 变量 -> 游标 -> 条件处理 .
DELIMITER $$
CREATE PROCEDURE payment_stat()
BEGIN
DECLARE i_staff_id INT ;
DECLARE d_amount DECIMAL(5,2);
DECLARE cur_payment CURSOR FOR SELECT staff_id,amount FROM payment ;
DECLARE EXIT HANDLER FOR NOT FOUND CLOSE cur_payment ;
SET @x1 = 0 ;
SET @x2 = 0 ;
OPEN cur_payment ;
REPEAT
FETCH cur_payment INTO i_staff_id,d_amount ;
IF i_staff_id = 2
THEN
SET @x1 = @x1 + d_amount ;
ELSE
SET @x2 = @x2 + d_amount ;
END IF ;
UNTIL 0 END REPEAT ;
CLOSE cur_payment ;
END ;
$$
DELIMITER ;
CALL payment_stat();
注意:变量,条件,处理程序,游标都是通过DECLARE定义的,但是顺序是由先后要求的.
变量和条件 必须声明在最前面,然后是游标的声明,最后才是处理程序的声明.
7.流程控制
1).IF语句
IF search_condition
THEN statement_list
[
ELSEIF search_condition
THEN statement_list
]
[
ELSE statement_list
]
END IF
2).CASE语句
CASE case_value
WHEN when_value THEN
statement_list
[
WHEN when_value THEN
statement_list
]
...
[
ELSE
statement_list
]
END CASE
或者
CASE WHEN search_condition THEN
statement_list
[
WHEN search_condition THEN
statement_list
]
...
[
ELSE
statement_list
]
END CASE
Demo : 改写游标demo中IF语句
CASE
WHEN i_staff_id = 2
THEN
SET @x1=@x1+d_amount ;
ELSE
SET @x2= @x2+d_amount ;
END CASE ;
或
CASE i_staff_id
WHEN 2
THEN
SET @x1 = @x1 + d_amount ;
ELSE
SET @x2 = @x2 + d_amount ;
END CASE ;
3).LOOP 语句
简单的循环,需要配合其他的语句定义来实现退出循环,通常使用LEAVE语句实现.
[begin_label:] LOOP
statement_list
END LOOP [end_label]
如果没有退出循环语句,就是个死循环.
4).LEAVE 语句
从标注的流程中退出,通常和BEGIN..END / 循环 一起使用.
Demo :
DELIMITER $$
CREATE PROCEDURE actor_insert()
BEGIN
SET @x = 0 ;
ins : LOOP
SET @x = @x+1;
IF @x=100
THEN
LEAVE ins ;
END IF ;
INSERT INTO actor(first_name,last_name)
VALUES('Test','201');
END LOOP ins ;
END ;
$$
DELIMITER ;
CALL actor_insert();
5).ITERATE 语句
必须用在循环中,表示跳过当前循环的剩下语句,进入下次循环.作用相当于Java中的continue.
Demo:
DELIMITER $$
CREATE PROCEDURE actor_insert()
BEGIN
SET @x = 0 ;
ins : LOOP
SET @x = @x + 1;
IF @x = 10
THEN
LEAVE ins ;
ELSEIF mod(@x,2) = 0
THEN
ITERATE ins ;
END IF ;
INSERT INTO actor (actor_id , first_name,last_name)
VALUES(@x*10,'Test',@x);
END LOOP ins ;
END ;
$$
DELIMITER ;
CALL actor_insert() ;
6).REPEAT 语句
有条件的循环语句,相当于Java中的do_while
不同的是REPEAT是满足条件时就退出循环,while是满足就执行.Repeat 和 do..while 一样,至少执行一次.
Demo参考游标的demo
7).WHILE 语句
[begin_label:] WHILE search_condition
DO statement_list
END WHILE [end_label]
总结:存储过程/函数的优势是可以将数据的处理放在数据库服务器上进行,避免将大量的结果集传输给客户端,减少数据传输,
但是在数据库服务器上进行大量的复杂运算会占用服务器的cpu,造成数据库服务器的压力,
所以存储过程/函数中不要进行大量的复杂运算,应该将这些运算操作分摊到应用服务器上执行.
- 12.Mysql存储过程和函数
12.存储过程和函数12.1 什么是存储过程和函数存储过程和函数是事先经过编译并存储在数据库中的一段SQL语句的集合,调用存储过程和函数简化应用开发人员的工作,减少数据在数据库和应用服务器之间的传输, ...
- MYSQL存储过程和函数学习笔记
学至Tarena金牌讲师,金色晨曦科技公司技术总监沙利穆课程笔记的综合. 1. 什么是存储过程和函数 将SQL语句放入一个集合里,然后直接调用存储过程和函数来执行已经定义好的SQL语句,通过存储过程和 ...
- Paip.断点调试MYSQL存储过程跟函数的解决方案大法
Paip.断点调试MYSQL存储过程跟函数的解决方案大法 作者Attilax , EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn ...
- Mysql存储过程和函数
Mysql存储过程和函数 基本概念: 创建存储过程和函数是指将经常使用的一组SQL语句的组合在一起,并将这些SQL语句当作一个整体存储在MySQL服务器中.例如,银行经常需要计算用户的利息.不同类别的 ...
- MySql存储过程与函数详解
存储过程和函数是在数据库中定义一些SQL语句的集合,然后直接调用这些存储过程和函数来执行已经定义好的SQL语句.存储过程和函数可以避免开发人员重复的编写相同的SQL语句.而且,存储过程和函数是在MyS ...
- mysql 存储过程,函数,触发器
存储过程和函数 mysql> HELP CREATE PROCEDURE; Name: 'CREATE PROCEDURE' Description: Syntax: CREATE [DEFIN ...
- MySql存储过程、函数
存储过程和函数是在数据库中定义一些SQL语句的集合,然后直接调用这些存储过程和函数来执行已经定义好的SQL语句.存储过程和函数可以避免开发人员重复的编写相同的SQL语句.而且,存储过程和函数是在MyS ...
- Mysql - 存储过程/自定义函数
在数据库操作中, 尤其是碰到一些复杂一些的系统, 不可避免的, 会用到函数/自定义函数, 或者存储过程. 实际项目中, 自定义函数和存储过程是越少越好, 因为这个东西多了, 也是一个非常难以维护的地方 ...
- MySQL 存储过程和函数
概述 一提到存储过程可能就会引出另一个话题就是存储过程的优缺点,这里也不做讨论,一般别人问我我就这样回答你觉得它好你就用它.因为mysql中存储过程和函数的语法非常接近所以就放在一起,主要区别就是函数 ...
随机推荐
- git 常用命令记录 -- 快捷&备忘
1.安装 略2.git拉取远程分支 git config user.name git config user.email git config --global user.name xxxx git ...
- iOS开发的调试技巧
关于本文: 1.模拟器的快捷键 2.覆盖安装注意事项 3.给模拟器相册增加照片 4.模拟器中程序的数据 5.安装旧版本的模拟器 6.模拟慢网速 7.异常断点与符号断点 1.模拟器的快捷键 常用的模拟器 ...
- 按钮UIButton的使用
一.使用概要 当添加一个按钮到你的界面,执行以下步骤: 1.在创建时设置按钮的类型. 2.提供一个标题字符串或图像,为您的内容适当调整按钮的大小. 3.连接一个或多个操作按钮的方法. 4.设置自动布局 ...
- Java集合--线程安全(CopyOnWrite机制)
5 Java并发集合 5.1 引言 在前几章中,我们介绍了Java集合的内容,具体包括ArrayList.HashSet.HashMap.ArrayQueue等实现类. 不知道各位有没有发现,上述集合 ...
- 三、js提交请求加载启动动画、请求完成成功回调、注销加载动画
1.通过Query post方式进行异步请求方法 jQuery.post(url, [data], [callback], [type]) 参数说明: url:发送请求地址 data:待发送 Key ...
- Vue - 引入本地图片的两种方式
第一种,只引入单个图片,这种引入方法在异步中引入则会报错. 比如需要遍历出很多图片展示时 <image :src = require('图片的路径') /> 第二种,可引入多个图片,也可引 ...
- scrapy 实现mysql 数据保存
开始用scrapy 爬取数据的时候 开始用同步操作始终会报1064 的错误 因为 mysql 语法和导入的字段不兼容 尝试了 n 次之后 开始用 异步爬取 虽然一路报错 但是还是能把数 ...
- 「CF650E」Clockwork Bomb
传送门 Luogu 解题思路 显然对于两棵树共有的边,我们不会动它. 考虑第二颗树中有和第一棵树不同的边怎么处理. 我们设 \(fa_1[u],fa_2[u]\) 分别代表 \(u\) 在两棵树中的父 ...
- JAVA 集合 List 分组的两种方法
CSDN日报20170219--<程序员的沟通之痛> [技术直播]揭开人工智能神秘的面纱 程序员1月书讯 云端应用征文大赛,秀绝招,赢无人机! JAVA 集合 List 分组的两种方法 2 ...
- vmware fusion 进入 BIOS
要进入bios有三种方法:1.>启动的时候按F2即可进入bios进行一些启动盘等选项的操作.但是,启动的时候很难第一时间按F2成功进入bios, 2.>修改vmware 进入bios之前的 ...