含义
存储过程类似一个函数,数据库中也支持循环语句和判断语句。我们可以将所有的逻辑、判断和SQL语句全部写在数据库上面,然后取个名字,当程序来操作的时候,可以直接通过这个名字,就能执行对应的功能;不用传大量的SQL语句。
存储过程
一、创建存储过程
关键字: procedure
代码:
create procedure proc_p1()
说明:
- create procedure:表示要创建存储。
- proc_p1:是创建存储的名字。
这样就创建了一个存储过程,名为proc_p1;但是此时里面并没内容。
二、创建存储过程内容
代码:
create procedure proc_p1() begin 内容放置位置 end
说明:
要操作的内容必须放在,begin和end之间。
案例:
数据库内容:
操作代码:
create procedure proc_p1() BEGIN select * from part; END
结果;生成的对象会存储在函数中;
三、调用存储过程
关键字:CALL
代码:
CALL proc_p1();
四、删除存储过程
代码:
drop procedure proc_p1;
问题:能否修改存储过程那?
答案是肯定的,但是却很繁琐,因此我们一般修改的时候,都是重写存储过程。
因此,针对修改我们的操作(也是重写):
delimiter $$drop procedure proc_p1 $$ create procedure proc_p1() BEGIN select * from part; END $$delimiter ;
分析:
即先删除,后写入。
问题:如果删除的时候,没有对应的存储过程那?
答案:会报错!
因此我们要避险这种情况出现。
delimiter $$drop procedure if EXISTS proc_p1 $$ create procedure proc_p1() BEGIN select * from part; END $$delimiter ;
分析:
增加了if EXISTS判断;它表示,如果后面的这个存储过程有则删除,反之不操作;这样避免报错,导致问题。
上面的代码都是简单的操作,再看下面的代码:
有参数的存储过程
一、参数 in
delimiter $$drop procedure if EXISTS proc_p1 $$ create procedure proc_p1( in i1 int ) BEGIN declare d1 int; declare d2 int default 2; set d1 = i1 + d2; END $$delimiter ;
分析:
in:表示进的,接收参数
declare:表示声变量。
int:表示变量类型
default:表示设置变量的初始值。
set:表示赋值操作,也可以理解为设置值。
自定义代码的结束符号
delimiter
drop procedure if EXISTS proc_p1; create procedure proc_p1() BEGIN select * from part; END
上面代码在Navicat下是能执行的,但是在终端上是要出问题的。
原因就是这个分号;上面的代码begin和end间代码,表示一个功能,都是整体传进去的,但是,代码在执行的时候,遇到分号;则表示此功能的代码执行完毕。所以导致后面的代码不执行,在终端的运行,因为分号的原因,会导致运行的时候出问题,所以,分号要是用在不对的位置,会造成很大的麻烦。
说明:
这个的意思就表示,以后的mysql语句都是以 $$为结束。注意:
自定义的时候不能将 \ 设置用来结束;\ 在终端会报错!可能是转义符的原因吧。
验证上面的说明:
在终端进入mysql客户端,当我们输入的代码不带分号的时候,结果,会一直处于等待命令的状态:
加上分号:出结果
问题:如果我们这样改动的话,获导致全局都受影响,因此我们可以让这种效果,只在指定范围有效,离开这个范围,有还原会之前?
所以,完整的代码:
delimiter $$ drop procedure if EXISTS proc_p1 $$ create procedure proc_p1( in i1 int ) BEGIN declare d1 int; declare d1 int; set d1 = i1 + d2; END $$ delimiter ;
说明:
我们在end后加上
$$
表示一个功能的代码结束,并在最后,又将设置还原会去。还是以分号结尾,这样其他代码不受影响
下面接着存储参数in分析
二、参数 out
代码:
delimiter $$ drop procedure if EXISTS proc_p1 $$ create procedure proc_p1( in i1 int, out i2 int ) BEGIN declare d2 int default 3; if i1 = 1 then set i2 = 100 + d2; elseif i1 = 2 THEN set i2 = 200 + d2; else set i2 = 1000 + d2; end if; END $$ delimiter ; -- 加入回话变量 @u; call proc_p1(1, @u); select @u;
结果:
- 说明:
@u:默认其值为 none;回话变量,相当于我们在外面创建了一个变量,并将引用传入 proc_p1函数,这个传入的引用会被 i2 接收,所以,间接的也相当于在给这个 @u 赋值。
- out:字面意思理解,出;有返回的意思。
三、参数 inout
delimiter $$ drop procedure if EXISTS proc_p1 $$ create procedure proc_p1( in i1 int, inout ii int, out i2 int ) BEGIN declare d2 int default 3; if i1 = 1 then set i2 = 100 + d2; set ii = ii + 1; elseif i1 = 2 THEN set i2 = 200 + d2; else set i2 = 1000 + d2; end if; END $$ delimiter ; -- 加入回话变量 @u; set @o = 5; call proc_p1(1, @o, @u); select @o,@u;
结果:
分析:
inout:从字面意思理解”进、出”,表示要接收一个带值的变量,同时函数执行完后,也会将对应的变量返回。
扩展:sql中@变量
带上一个@叫用户变量:只要用户还登录着,这个变量就有效;不管在那个代码块中都有效;除非用户被关闭。
带上2个@叫全局变量。
注意:用户变量和函数的局部变量的区别
- 用户变量:只要用户还登录着,这个变量就有效;不管在那个代码块中都有效;除非用户被关闭。
- 局部变量:离开函数就没用了。
python操作数据库存储过程
#!/usr/bin/env python # -*- coding:utf-8 -*- import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 执行存储过程 cursor.callproc('proc_p1', (1,2,3)) # 获取执行完存储的参数 cursor.execute("select @_p1_0,@_p1_1,@_p1_2,@_p1_3") result = cursor.fetchall() conn.commit() cursor.close() conn.close() print(result)
说明:
cursor.callproc(‘proc_p1’, (1,2,3)):只能给数据库中的proc_p1存储方法;根据前面的我们知道数据库中的proc_p1;只能接收2个参数,所以,即使你传入了3个也只有2个能用。后面的会自动忽略。
上面的数据库中的存储过程,没有SQL语句,只是简单的,变量操作,但是,如果我们加入SQL操作,那我们在python中怎样获取这个SQL语句操作的结果那?
获取存储过程的查询结果:
cursor.fetchall()
问题:怎样获取变量的返回值那?
cursor.execute("select @_p1_0”)
分析:
1、首先要用select
。
2、一个@_
3、后面在接存储过程的名字。
4、接 _0:表示索引。表示获取返回第一个值,要想获取后面的,则依次往后指定,用逗号
隔开便可。cursor.execute("select @_p1_0,@_p1_1,@_p1_2,@_p1_3")
这个获取获的值,存放在游标里面的,所以,要获取具体的值,可以通过游标结合fetchone获取:
result = cursor.fetchone()
特殊:
虽然存储过程中,in接收参数,但是在python中获取存储过程数据的时候,in接收传入的值,会被返回,所以,获取的第一个值,便是,callproc
执行的时候,传入的第一个参数.
python获取存储过程分两步:
- 获取SQL语句执行的返回值
- 获取存储函数的变量返回值