MySQL存储过程
- 本文用python执行SQL语句。
导入python库
import json
import pymysql
from pymysql.converters import escape_string
import pandas as pd
连接数据库
#连接数据库
conn=pymysql.connect(
host="localhost",
port=3306,#端口号
user="root",#数据库用户
password="123456",#数据库密码
#database="world"#要连接的数据库名称
)
cur=conn.cursor()
跳转到指定数据库
sql = """USE PLJNB"""
cur.execute(sql)
cur.fetchall()
介绍
将SQL语句封装并重用,提高数据处理效率
特点:
- 封装、复用
- 可以接收参数,也可以返回数据
- 减少网络交互,提升效率
创建存储过程
- 在命令行中,执行创建存储过程的SQL时,需要通过关键字delimiter指定SQL结束符。
- 例:
delimiter $$ :表示以该命令行$$为SQL结束符
CREATE PROCEDURE 存储过程名称([参数列表])
BEGIN
--SQL语句
END;
- 例:
sql = """
CREATE PROCEDURE p1()
BEGIN
SELECT COUNT(*) FROM student;
END;
"""
cur.execute(sql)
cur.fetchall()
调用存储过程
CALL 名称([参数]);
- 例:
sql = """
CALL p1();
"""
cur.execute(sql)
pd.DataFrame(list(cur.fetchall()),columns=[i[0] for i in cur.description])
查看存储过程
查询指定数据库的存储过程及状态信息
SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = '数据库名'
查询某个存储过程的定义
SHOW CREATE PROCEDURE 存储过程名称;
删除某个存储过程
DROP PROCEDURE [IF EXISTS] 存储过程名称;
变量
系统变量
- MySQL服务器提供,不是用户定义的,分为全局变量(GLOBAL)、会话变量(SESSION)。
- 服务重启后,所设置的全局变量会失效,若想不失效,需在/etc/my.cnf中设置。
查看系统变量
- 查看所有系统变量:
SHOW [SESSION|GLOBAL] VARIABLES;
- 模糊查找变量:
SHOW [SESSION|GLOBAL] VARIABLES LIKE '...'
- 查看指定变量:
SELECT @@[SESSION|GLOBAL].系统变量名;
设置系统变量
SET [SESSION|GLOBAL] 系统变量名 = 值;
或
SET @@[SESSION|GLOBAL].系统变量名 = 值;
用户定义变量
- 用户变量赋值时用:=以区分判断=
- 用户根据自己需要定义的变量,用"@变量名"定义即可,作用域为当前会话
- 不需要初始化,也不需要提前声明,不初始化时取值为NULL
用户变量赋值
SET @变量名 = 值 [,@变量名 = 值]...;
或
SET @变量名 := 值 [,@变量名 := 值]...;
或
SELECT @变量名 := 值 [,@变量名 := 值]...;
或
SELECT 字段名 INTO @变量名 FROM 表名;
用户变量使用
SELECT @变量名;
局部变量
- 在存储过程内使用的局部变量,需要DECLARE声明
局部变量声明
DECLARE 变量名 变量类型 [DEFAULT...];(变量类型:INT、BIGINT等)
局部变量赋值
SET 变量名 = 值;
或
SET 变量名 := 值;
或
SELECT 字段名 INTO 变量名 FROM 表名...;
- 例:
sql = """
CREATE PROCEDURE p2()
BEGIN
DECLARE stu_count INT DEFAULT 1;
SELECT COUNT(*) INTO stu_count FROM student;
SELECT stu_count;
END;
"""
cur.execute(sql)
cur.fetchall()
存储过程的参数
参数类别
参数关键字 | 作用 |
---|---|
IN | 该类参数作为输入,也就是需要调用时传入值 |
OUT | 该类参数作为输出,也就是该参数可以作为返回值 |
INOUT | 既可以作为输入参数,也可以作为输出参数 |
含参存储过程的创建
CREATE PROCEDURE 存储过程名称([IN/OUT/INOUT 参数名 参数类型])
BEGIN
--SQL语句
END;
- 例:
sql = """
CREATE PROCEDURE p4(IN age INT,OUT age_rank VARCHAR(10))
BEGIN
IF age >= 23 THEN
SET age_rank := '99年';
ELSEIF age >= 22 THEN
SET age_rank := '00年';
ELSE
SET age_rank := '00后';
END IF;
SELECT age_rank;
END;
"""
cur.execute(sql)
cur.fetchall()
含参存储过程的执行
SET @用户变量 = '默认值';
CALL 存储过程名(输入值, @用户变量);
SELECT @用户变量;
存储过程的逻辑函数-IF
IF 条件1 THEN
-- 满足条件1,执行此SQL
ELSEIF 条件2 THEN
-- 满足条件2,执行此SQL
ELSE
-- 否则执行此SQL
END IF;
- 例:
sql = """
CREATE PROCEDURE p4(IN age INT,OUT age_rank VARCHAR(10))
BEGIN
IF age >= 23 THEN
SET age_rank := '99年';
ELSEIF age >= 22 THEN
SET age_rank := '00年';
ELSE
SET age_rank := '00后';
END IF;
SELECT age_rank;
END;
"""
cur.execute(sql)
cur.fetchall()
存储过程的逻辑函数-CASE
写法一
CASE case变量
WHEN 值1 THEN SQL语句1 (若case变量=值1,则执行SQL语句1)
WHEN 值2 THEN SQL语句2 (若case变量=值2,则执行SQL语句2)
ELSE SQL语句3 (否则执行SQL语句3)
END CASE;
写法二
CASE
WHEN 判断语句1 THEN SQL语句1 (判断语句1为真,则执行SQL语句1)
WHEN 判断语句2 THEN SQL语句2 (判断语句2为真,则执行SQL语句2)
ELSE SQL语句3 (否则执行SQL语句2)
END CASE
- 例:
sql = """
CREATE PROCEDURE p5(IN age INT,OUT age_rank VARCHAR(10))
BEGIN
CASE
WHEN age >= 23 THEN SET age_rank := '99年';
WHEN age >= 22 THEN SET age_rank := '00年';
ELSE SET age_rank := '00后';
END CASE;
END;
"""
cur.execute(sql)
cur.fetchall()
存储过程的逻辑函数-WHILE
WHILE 条件 DO
SQL逻辑...
END WHILE;
- 例:
sql = """
CREATE PROCEDURE pwhile(IN n INT,INOUT result INT)
BEGIN
DECLARE i INT DEFAULT 0;
WHILE i <= n DO
SET result := result + 2;
SET i := i + 1;
END WHILE;
SELECT result;
END;
"""
cur.execute(sql)
cur.fetchall()
存储过程的逻辑函数-REPEAT
REPEAT
SQL逻辑...
UNTIL 条件 (满足则退出)
END REPEAT;
- 例:
sql = """
CREATE PROCEDURE prepeat(IN n INT,INOUT result INT)
BEGIN
DECLARE i INT DEFAULT 0;
REPEAT
SET result := result + 2;
SET i := i + 1;
UNTIL i > n
END REPEAT;
SELECT result;
END;
"""
cur.execute(sql)
cur.fetchall()
存储过程的逻辑函数-LOOP
循环体
[标记:]LOOP (标记用于标识loop循环)
SQL逻辑...
END LOOP [标记];
循环逻辑
LEAVE 标记; 退出指定标记的循环体
ITERATE 标记; 直接进入下一次循环
- 例:
sql = """
CREATE PROCEDURE ploop(IN n INT,INOUT result INT)
BEGIN
DECLARE i INT DEFAULT 0;
sum:LOOP
IF i > n THEN
LEAVE sum;
END IF;
SET result := result + 2;
SET i := i + 1;
END LOOP sum;
SELECT result;
END;
"""
cur.execute(sql)
cur.fetchall()
游标
介绍
- 游标是用来存储查询结果集的数据类型
- 在存储过程和函数中可以使用游标对结果集进行循环的处理
- 用法在“条件存储程序”的例子中
声明游标
DECLARE 游标名称 CURSOR FOR 查询语句; (查询语句的结果集存储在游标中)
打开游标
OPEN 游标名称;
获取游标记录
FETCH 游标名称 INTO 变量[,变量];
关闭游标
CLOSE 游标名称;
条件存储程序
- 用来定义再流程控制结构执行过程中遇到问题时相应的处理步骤(异常处理)
定义条件处理程序
程序主体是SQL语句,SQL语句前的关键字指定异常处理类型和条件。
DECLARE handler_action HANDLER FOR condition_value SQL语句;
handler_action (条件处理程序的类型)
条件处理程序类型的关键字 | 作用 |
---|---|
CONTINUE: | 继续执行当前程序 |
EXIT: | 终止执行当前程序 |
condition_value (条件):
条件的关键字 | 作用 |
---|---|
SQLSTATE sqlstate_value(状态码,如02000) | 指定状态码 |
SQLWARNING | 所有以01开头的SQLSTATE状态码 |
NOT FOUND | 所有以02开头的SQLSTATE状态码 |
SQLEXCEPTION | 所有其他开头的SQLSTATE状态码 |
- 例:查找user表中年龄小于uage的记录,复制到user_pro表中。
sql = """
CREATE PROCEDURE p11(IN uage INT)
BEGIN
DECLARE uname VARCHAR(100);
DECLARE u_cursor CURSOR FOR SELECT name,age FROM user WHERE age <= uage;
DECLARE EXIT HANDLER FOR SQLSTATE '02000' CLOSE u_cursor;
DROP TABLE IF EXISTS user_pro;
CREATE TABLE IF NOT EXISTS user_pro(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
age INT
);
OPEN u_cursor;
WHILE TRUE DO
FETCH u_cursor INTO uname,uage;
INSERT INTO user_pro VALUES (NULL,uname,uage);
END WHILE;
CLOSE u_cursor;
END;
"""
cur.execute(sql)
cur.fetchall()
存储函数
介绍
- 是有返回值的存储过程
- 存储函数的参数只能是IN类型
创建存储函数
CREATE FUNCTION 存储函数名称([参数列表])
RETURNS 返回值类型 [characteristic...]
BEGIN
--SQL语句
RETURN...;
END;
characteristic(特性)
条件的关键字 | 作用 |
---|---|
DETERMINISTIC | 相同的输入参数总是产生相同的结果 |
NO SQL | 不包含SQL语句 |
READS SQL DATA | 包含读取数据的语句,但不包含写入数据的语句 |
- 例:求n个2的和
sql = """
CREATE FUNCTION floop(n INT)
RETURNS INT DETERMINISTIC
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE result INT DEFAULT 0;
sum:LOOP
IF i > n THEN
LEAVE sum;
END IF;
SET result := result + 2;
SET i := i + 1;
END LOOP sum;
RETURN result;
END;
"""
cur.execute(sql)
cur.fetchall()
执行存储函数
SELECT 存储函数名();