在mysql存储过程中动态拼接sql并执行

在备份、迁移、恢复数据库的时候,要从mysql8.0版本迁移到5.7版本库中,在迁移的过程中有些表字段设置了字符类型为 utf8mb4_0900_ai_ci ,但这个字符类型在5.7中是没有的,因此如果一个一个去改怕是改一个月去了。有些同学使用代码编程,在项目中连接数据库去修改,也是可以的,但是我不想这么麻烦,就用了存储过程。下面介绍怎么用存储过程批量修改表字段字符类型。

1.首先写一个sql查看哪些表和字段需要修改:

sql 复制代码
SELECT TABLE_NAME, COLUMN_NAME,DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,COLUMN_TYPE,COLUMN_COMMENT COLLATION_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'test' and collation_name = 'utf8mb4_0900_ai_ci';

2.然后编写一个存储过程脚本,去批量修改:

sql 复制代码
drop procedure if exists modify_collation;

DELIMITER //
create PROCEDURE modify_collation(out origin_num int(10),out count_num int(10))
COMMENT 'modify_collation' 
SQL SECURITY DEFINER
BEGIN
	DECLARE t_name VARCHAR(100);
	declare c_name VARCHAR(100);
	declare c_type VARCHAR(20);
	declare c_comment VARCHAR(255);
-- 	declare tem_sql text;
	declare done int(10) default 0;
	declare collation_cursor cursor for SELECT table_name, column_name,COLUMN_TYPE,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS 
	WHERE TABLE_SCHEMA = 'test' and collation_name = 'utf8mb4_0900_ai_ci';
	
	declare continue handler for not found set done = 1;
	
	select count(1) into origin_num from INFORMATION_SCHEMA.COLUMNS
	WHERE TABLE_SCHEMA = 'test' and collation_name = 'utf8mb4_0900_ai_ci';
		
	open collation_cursor ;
	set count_num := 0;
	mylp:loop
		FETCH collation_cursor into t_name,c_name,c_type,c_comment;
		
 		set @sql = concat('ALTER TABLE ',t_name,' MODIFY ',c_name,' ', c_type,' CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci comment "',c_comment,'"');
	 --	PREPARE stmt FROM @sql;
	 --	EXECUTE stmt;
	 --	DEALLOCATE PREPARE stmt;
	    select @sql;
		if done = 1 then
		 leave mylp;
		end if;
		set count_num := count_num +1;
	end loop;

	close collation_cursor;
end//
DELIMITER ;

这里我们先把这三句话注释掉,执行存储过程,打印看是否拼接出来的sql没有语法错误。

sql 复制代码
     --	PREPARE stmt FROM @sql;
	 --	EXECUTE stmt;
	 --	DEALLOCATE PREPARE stmt;

执行存储过程

sql 复制代码
call modify_collation(@num,@count_num);

打印出来是这样,就说明拼接的sql是正常的,没有语法错误。

sql 复制代码
ALTER TABLE t_open MODIFY action char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci comment "动作。1:开门;2:关门"

**注意:**里面的变量 @sql 如果换成局部变量居然无法通过sql语法。

3.把上面那三个注释去掉,注掉打印的语句再来执行存储过程

sql 复制代码
drop procedure if exists modify_collation;

DELIMITER //
create PROCEDURE modify_collation(out origin_num int(10),out count_num int(10))
COMMENT 'modify_collation' 
SQL SECURITY DEFINER
BEGIN
	DECLARE t_name VARCHAR(100);
	declare c_name VARCHAR(100);
	declare c_type VARCHAR(20);
	declare c_comment VARCHAR(255);
-- 	declare tem_sql text;
	declare done int(10) default 0;
	declare collation_cursor cursor for SELECT table_name, column_name,COLUMN_TYPE,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS 
	WHERE TABLE_SCHEMA = 'test' and collation_name = 'utf8mb4_0900_ai_ci';
	
	declare continue handler for not found set done = 1;
	
	select count(1) into origin_num from INFORMATION_SCHEMA.COLUMNS
	WHERE TABLE_SCHEMA = 'test' and collation_name = 'utf8mb4_0900_ai_ci';
		
	open collation_cursor ;
	set count_num := 0;
	mylp:loop
		FETCH collation_cursor into t_name,c_name,c_type,c_comment;
		
 		set @sql = concat('ALTER TABLE ',t_name,' MODIFY ',c_name,' ', c_type,' CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci comment "',c_comment,'"');
	 	PREPARE stmt FROM @sql;
	 	EXECUTE stmt;
	 	DEALLOCATE PREPARE stmt;
	--  select @sql;
		if done = 1 then
		 leave mylp;
		end if;
		set count_num := count_num +1;
	end loop;

	close collation_cursor;
end//
DELIMITER ;

执行存储过程

sql 复制代码
call modify_collation(@num,@count_num);
select@num,@count_num;

从打印结果可以看到执行的条数和查询的数量是一样的,说明已经全部修改完了。

虽然最后执行完了,但是这个存储过程执行的有点太慢了,执行完我看了一下,时间用了108秒多, 你们有什么办法可以把这个过程执行的速度快一点呢?

参考:

1.MySQL动态SQL的拼接以及执行、分页 - 竹根七 - 博客园 (cnblogs.com)

2.批量修改mysql 所有表字段的 排序规则_mob64ca12eea322的技术博客_51CTO博客

相关推荐
2603_965148119 小时前
如何解析JSON数据?API返回的商品信息处理教程
开发语言·数据库·python·自动化·json·api
ltl9 小时前
RocksDB 经典故障排查:L0、compaction 与 write stall
数据库
xfhuangfu10 小时前
Oracle中建立到CDB和PDB的连接
数据库·oracle·rpc
小小龙学IT10 小时前
DuckDB 深度实战:用 C++ 在进程内跑一个「分析型数据库」
数据库·c++
NineData10 小时前
DTCC 2026 预告|NineData CEO& 创始人叶正盛:面向 AI Agent 的数据库 DevOps 与数据复制实践
数据库·人工智能·数据库开发·devops·ninedata·数据库技术·dtcc
J_bean11 小时前
MySQL 事务是否必须手动开启?
数据库·mysql·数据库事务·自动提交·手动提交
J_bean11 小时前
MySQL InnoDB 如何检测死锁、判定死锁、处理死锁
数据库·mysql·死锁·死锁检测·处理死锁·死锁判定
浪子明X11 小时前
从 MongoDB 文档到关系模型:构建可重跑、可对账的数据迁移流水线
数据库·mongodb·oracle
杜子不疼.12 小时前
国产数据库撑起固井软件自主化:金仓 × 中海油服「海恒 Cemsol」落地解析
数据库
隔窗听雨眠12 小时前
GBase 8s并发控制深度解析:封锁机制、隔离级别与死锁处理全攻略
服务器·数据库·oracle