mysql存储过程之遍历设置表中某些字段值

缘起

​ mysql数据库中有用到分表,大概300张表,都是以geo_data_xxxxxx来命名,之前测试过程中,有给300张表中的一个字段设置过值,但是想重新生成一遍数据。那么后面是做了一个数据清洗,给300张表is_turnout字段设置成null值。若要一个一个表update,工作量也确实有点大了。

可以用mysql的存储过程来实现。

操作

大致思路:

  • 先查到geo_data_xxxxxx的所有表的表名
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '库名' AND TABLE_NAME REGEXP 'geo_data_[0-9]'
  • 遍历循环,执行update即可
update 表名 set is_turnout = null

好像挺完美。

完整语句如下:

DROP PROCEDURE IF EXISTS set_geo_turnout_null;
CREATE PROCEDURE set_geo_turnout_null()
BEGIN
	-- 该变量用于标识是否还有数据需遍历
	DECLARE flag INT DEFAULT 0;
	-- 创建一个变量用来存储遍历过程中的值
	DECLARE tbl_name VARCHAR(100);
	-- 查询出需要遍历的数据集合
	DECLARE tbl_list CURSOR FOR (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '库名' AND TABLE_NAME REGEXP 'geo_data_[0-9]');
	-- 查询是否有下一个数据,没有将标识设为1,相当于hasNext
	DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = 1;
	-- 打开游标
	OPEN tbl_list;
		-- 取值设置到临时变量中
		FETCH tbl_list INTO tbl_name;
		-- 遍历未结束就一直执行
		WHILE flag != 1 DO
				-- targetSQL //你想要执行的目标功能,这里可以写多个SQL
				update tbl_name set is_turnout = null;
				-- 一定要记得把游标向后移一位
				FETCH tbl_list INTO tbl_name;
		END WHILE;
	-- 关闭游标
	CLOSE tbl_list;
END;

欧克,信心满满,执行完然后速度调用,嘿嘿

CALL set_geo_turnout_null();

在这里插入图片描述

嘎?

在这里插入图片描述

什么玩意儿啊,不讲武德的,这都能错吗??

排错

首先从问题来看,就是执行update的时候,我的变量tbl_name它没有被解析出来,而是被当成了一个字符串。

在这里插入图片描述

后面又想着,既然表名是一个变量,那么我可以进行拼接吗,update concat('geo_data_','111111'),执行了一手,真不行吧。

经过查阅资料,可以使用mysql的动态sql来实现,类似如下:

SET @table_name = 'your_table_name';
SET @sql = CONCAT('UPDATE ', @table_name, ' SET column1 = value1, column2 = value2 WHERE condition');

PREPARE stmt FROM @sql;
EXECUTE stmt;

欧克,赶紧尝试一手。

DROP PROCEDURE IF EXISTS set_geo_turnout_null;
CREATE PROCEDURE set_geo_turnout_null()
BEGIN
	-- 该变量用于标识是否还有数据需遍历
	DECLARE flag INT DEFAULT 0;
	-- 创建一个变量用来存储遍历过程中的值
	DECLARE tbl_name VARCHAR(100);
	-- 查询出需要遍历的数据集合
	DECLARE tbl_list CURSOR FOR (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '库名' AND TABLE_NAME REGEXP 'geo_data_[0-9]');
	-- 查询是否有下一个数据,没有将标识设为1,相当于hasNext
	DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = 1;
	-- 打开游标
	OPEN tbl_list;
		-- 取值设置到临时变量中
		FETCH tbl_list INTO tbl_name;
		-- 遍历未结束就一直执行
		WHILE flag != 1 DO
				-- targetSQL //你想要执行的目标功能,这里可以写多个SQL
				SET @sql = CONCAT('UPDATE ', tbl_name, ' SET is_turnout = null');
				PREPARE stmt FROM @sql;
				EXECUTE stmt;
				-- 一定要记得把游标向后移一位,这个坑我替各位踩过了,不需要再踩了
				FETCH tbl_list INTO tbl_name;
		END WHILE;
	CLOSE tbl_list;
END;

保存,调用…成功了~~

在这里插入图片描述

优化+日志

笔者也是深受封装思想的影响,见到乱七八糟的东西,就想给它打包带走。

也就是一个存储过程给拆解成两个就行了。那么我可以将update的动态sql封装起来,设置为一个存储过程;然后循环表设置字段值又是一个存储过程,最后再调用下update存储过程就行了。

update动态sql,接收一个table_name的入参

DROP PROCEDURE IF EXISTS update_table_geo;
CREATE PROCEDURE update_table_geo(IN table_name VARCHAR(255))
BEGIN
	-- 日志
	select table_name;
	-- 动态sql语句
    SET @sql = CONCAT('UPDATE ', table_name, ' SET is_turnout = null');
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
END

循环处理存储过程

DROP PROCEDURE IF EXISTS set_geo_turnout_null;
CREATE PROCEDURE set_geo_turnout_null()
BEGIN
	-- 该变量用于标识是否还有数据需遍历
	DECLARE flag INT DEFAULT 0;
	-- 创建一个变量用来存储遍历过程中的值
	DECLARE tbl_name VARCHAR(100);
	-- 查询出需要遍历的数据集合
	DECLARE tbl_list CURSOR FOR (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '库名' AND TABLE_NAME REGEXP 'geo_data_[0-9]');
	-- 查询是否有下一个数据,没有将标识设为1,相当于hasNext
	DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = 1;
	-- 打开游标
	OPEN tbl_list;
		-- 取值设置到临时变量中
		FETCH tbl_list INTO tbl_name;
		-- 遍历未结束就一直执行
		WHILE flag != 1 DO
				-- targetSQL //你想要执行的目标功能,这里可以写多个SQL
				-- 执行 update 动态sql
				call update_table_geo(tbl_name);
				-- 一定要记得把游标向后移一位
				FETCH tbl_list INTO tbl_name;
		END WHILE;
	CLOSE tbl_list;
END;

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果你在 Node.js 中使用 MySQL,并且有一个包含父子关系的表,你可以使用递归查询来返回树状结构。以下是一个示例,假设我们有一个表 `departments`,其中包含 `id`,`name` 和 `parent_id` 这三个字段,`parent_id` 表示父部门的 `id`。 首先,我们需要使用 MySQL 模块连接到数据库。在示例中,我们使用 `mysql2` 模块连接到数据库,你也可以使用其他的 MySQL 模块。 ```js const mysql = require('mysql2'); const connection = mysql.createConnection({ host: 'localhost', user: 'root', password: 'password', database: 'test' }); ``` 然后,我们可以使用递归函数来获取树状结构。以下是一个示例递归函数: ```js async function getDepartmentTree(parentId) { const [rows] = await connection.promise().query( 'SELECT id, name, parent_id FROM departments WHERE parent_id = ?', [parentId] ); const departments = []; for (const row of rows) { const department = { id: row.id, name: row.name, children: await getDepartmentTree(row.id) }; departments.push(department); } return departments; } ``` 该函数接收一个参数 `parentId`,表示要查询的父部门的 `id`。首先,该函数从数据库中查询所有 `parent_id` 为 `parentId` 的部门,并将查询结果存储在 `rows` 中。 然后,该函数使用一个循环遍历 `rows`,对于每个部门,它创建一个包含 `id`、`name` 和 `children` 的对象。`id` 和 `name` 来自查询结果,`children` 是一个递归调用 `getDepartmentTree` 的结果,其中传入的参数是当前部门的 `id`。递归调用会继续向下查询子部门,并返回子部门的树状结构。 最后,该函数返回一个数组 `departments`,其中包含所有查询到的部门的树状结构。如果要查询根节点的树状结构,可以将 `parentId` 设置为 `null`。 以下是一个示例调用该函数并打印结果: ```js (async () => { const departmentTree = await getDepartmentTree(null); console.log(JSON.stringify(departmentTree, null, 2)); })(); ``` 该调用会返回所有部门的树状结构,并将其以 JSON 格式打印出来。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值