🍁6.4、conn.cursor()
概念:
这个函数是pymysql用来调用存储过程的,语法如下:
conn.cursor('存储过程的名称')
示例【还是用上面的class表】:
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='@123456', db='testdb', charset='utf8') # 创建游标 cursor = conn.cursor() # 调用存储过程p1 cursor.callproc('p1') conn.commit() print(cursor.fetchall()) cursor.close() conn.close() 输出结果: ((1, '三年一班'), (2, '三年四班'), (3, '五年一班'), (4, '六年二班'), (5, '七年二班'), (6, 'teacher触发产生'), (7, '触发产生'), (8, '触发产生'), (9, '调用了存储过程'), (10, '调用了存储过程'))
🍁6.5、删除存储过程
语法:
DROP PROCEDURE [IF EXISTS] 存储过程名
🍁6.6、查看存储过程
- 使用SHOW CREATE语句查看存储过程和函数的创建信息
语法:
SHOW CREATE PROCEDURE 存储过程名
- 使用SHOW STATUS语句查看存储过程和函数的状态信息:
这个语句返回子程序的特征,如数据库、名字、类型、创建者及创建和修改日期。
[LIKE 'pattern']
匹配存储过程的名称,可以省略。当省略不写时,会列出MySQL数据库中存在的所有存储过程的信息。
语法:
SHOW PROCEDURE STATUS [LIKE 'pattern']
3、使用SHOW STATUS语句查看存储过程和函数的状态信息:
MySQL中存储过程的信息存储在information_schema数据库下的Routines表中。可以通过查询该表的记录来查询存储过程和函数的信息。
语法结构:
SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME='存储过程的名' [AND ROUTINE_TYPE = 'PROCEDURE'];
说明: 如果在MySQL数据库中存在存储过程和函数名称相同的情况
,最好指定ROUTINE_TYPE
查询条件来指明查询的是存储过程还是函数。
🍁6.7、修改存储过程
修改存储过程,不影响存储过程功能,只是修改相关特性。使用ALTER语句实现。
ALTER PROCEDURE 存储过程名;
🍁6.8、pymysql实现拿结果集
我使用6.3中2、调用out模式的参数:的存储过程的栗子
存储过程:
delimiter // create procedure p2( in n1 int, out n2 char(15) ) begin set n2 = "在存储过程中改变"; SELECT * FROM class WHERE cid > n1; end // delimiter ;
python代码
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='@123456', db='testdb', charset='utf8') # 创建游标 cursor = conn.cursor() # 调用存储过程,并且传参数 cursor.callproc('p2', (8,"开始值")) print(cursor.fetchall()) # 拿到结果集 cursor.execute('select @_p2_0,@_p2_1') print(cursor.fetchall()) cursor.close() conn.close() 输出结果: ((9, '调用了存储过程'), (10, '调用了存储过程')) ((8, '在存储过程中改变'),)
cursor.execute('select @_p2_0,@_p2_1')
@_p2_0表示拿p2中第一个参数,因为第一个参数是in得到的就是传入的值,@_p2_0_1表示拿p2中第二个参数,因为第二个参数是out所以得到的就是在存储过程中发生改变后的变量的值,,
如果是inout的话就会根据变量在存储过程中是否发生改变而返回对应的结果【不改变的话就是传入的参数,改变的就是在存储过程中发生改变的值】
我们也可以如下的方法:
set @_v1_0 = 8; set @_v1_1 = "开始值"; call p2(@_v1_0, @_v1_1); select @_v1_0, @_v1_1; 输出结果: 结果一 结果二 +---------------------+ +--------------------+ cid caption @_v1_0 @_v1_1 9 调用了存储过程 8 在存储过程中改变 10 调用了存储过程 +---------------------+ +---------------------+
6.9、其他拓展内容
⚡6.9.1、LOOP实现
实现的需求,假如我有一张A表如下
id num 1 9 2 8 3 4
要实现循环拿到A表中每一行的id与num 并且将他们的值分别对应相加放到B表中的num列
实现的B表示例如下:
id num 1 10 2 10 3 7
实现答案:
delimiter // create procedure p6() begin -- 自定义变量用来存储每一行id值 declare row_id int; declare row_num varchar(50); -- 如果done为false表示还没有终止,下面的游标还能继续执行 declare done int default false; declare temp int -- 去A表中逐行取数据,相当于遍历A表中的每一行 declare my_cursor cursor for select id, num from A; -- 游标终止的条件 ,检测当A表中没有数据done = ture就退出 declare continue handler for not found set done = ture; -- 创建游标 open my_cursor; -- 表示开启循环 loop表示循环 loop_label: LOOP fetch my_cursor into row_id, row_num; IF done THEN LEAVE loop_label; END IF; set temp = row_id + row_num; INSERT INTO B(num) VALUES(temp); -- 循环终止的条件 END LOOP loop_label; end // delimiter ;
⚡6.9.2、条件语句
delimiter \\ -- 创建一个条件存储过程 CREATE PROCEDURE proc_if () BEGIN declare i int default 0; if i = 1 THEN SELECT 1; ELSEIF i = 2 THEN SELECT 2; ELSE SELECT 7; END IF; END\\ delimiter ;
⚡6.9.3、while循环
delimiter \\ CREATE PROCEDURE proc_while () BEGIN DECLARE num INT ; SET num = 0 ; WHILE num < 10 DO SELECT num ; SET num = num + 1 ; -- 结束的标识就是while不满足 END WHILE ; END\\ delimiter ;
⚡6.9.4、repeat循环
delimiter \\ CREATE PROCEDURE proc_repeat () BEGIN DECLARE i INT ; SET i = 0 ; repeat select i; set i = i + 1; until i >= 5 end repeat; END\\ delimiter ;
🍁6.10、动态执行SQL
目的:防SQL注入
实现:
delimiter \\ DROP PROCEDURE IF EXISTS proc_sql \\ CREATE PROCEDURE proc_sql () BEGIN declare p1 int; set p1 = 11; -- 必须要写,在下面using后才不会报错 set @p1 = p1; -- 预检测某个东西 SQL语句的合法性,prod为自定义的变量 PREPARE prod FROM 'select * from tb2 where nid > ?'; -- @p1表示用p1的值替换上一行语句中的?号 EXECUTE prod USING @p1; -- 执行上面的已经格式化完成的SQL语句 DEALLOCATE prepare prod; END\\ delimiter ;
🍁6.11、支持事务的存储过程
事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。
delimiter \\ create PROCEDURE p1( -- p_return_code根据值的不同用来表示状态 OUT p_return_code tinyint ) BEGIN -- 设置发生SQL异常退出 DECLARE exit handler for sqlexception BEGIN -- ERROR(错误时返回1) set p_return_code = 1; -- 回滚到未发生错误时的初始状态 rollback; END; -- 设置发生SQL警告退出 DECLARE exit handler for sqlwarning BEGIN -- WARNING(警告时返回2) set p_return_code = 2; -- 回滚到初始状态 rollback; END; -- START TRANSACTION立即启动一个事务,而不管当前的提交模式设置如何。 -- 无论当前的提交模式设置如何,以START transaction开始的事务必须通过 -- 发出显式COMMIT或ROLLBACK来结束。 START TRANSACTION; DELETE from tb1; insert into tb2(name)values('seven'); -- 因为没有发生错误,就将更改的数据提交 COMMIT; -- SUCCESS(成功时返回0) set p_return_code = 0; END\\ delimiter ;
🍀7、其他
MySQL中如果对性能的要求比较高的话,一般是不推荐使用函数的,因为函数的使用可能会破坏索引加速查找的效果。可以在程序或者架构级别使用函数操作,有创建函数的想法时先看看有没有内置函数可以满足,避免重复造轮子😀