MySQL 中将使用逗号分隔的字段转换为多行数据

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 在开发中,遇到逗号分隔字段的处理是常见问题。本文通过一个实际场景展示了如何改造数据存储:从单一字段存储多个页面(如`page1,page2,page3`)到使用新表`bus_pages`存储每个页面的详细配置。使用`SUBSTRING_INDEX`函数配合`help_topic`表(具有连续ID)拆分`bus_mark_info`表中的`pages`字段,按`help_topic_id`截取页面名称并插入新表。当`pages`字段超过701个页面时,需寻找其他辅助表。最终,数据成功迁移到新结构中,便于单独配置每个页面。

在我们的实际开发中,经常需要存储一些字段,它们使用像, - 等连接符进行连接。在查询过程中,有时需要将这些字段使用连接符分割,然后查询多条数据。今天,我们将使用一个实际的生产场景来详细解释这个解决方案。

04981b82946c4eb4a9bf75845a32d968_1.png

场景介绍

最近我们对一个需求进行了改造。在此之前,我们有一个工单信息表名为bus_mark_info,其中包含一个配置字段pages。以前,为了方便配置,配置人员直接将多个页面使用逗号连接后保存,就像是将page1, page2, page3等直接存储在了该字段中。随着业务的发展,我们现在需要对每个页面进行单独配置,并添加一些其他属性。为了实现这一需求,我们在bus_mark_info表中添加了一个关联表bus_pages。在上线时,我们需要将已有的pages字段中配置历史数据的页面值使用逗号进行分割,并存入新的表中,然后废弃掉工单信息表中的pages字段。bus_mark_info表数据如下:
_20240402220850.jpg

查询SQL 语句编写

我们首先是将要新增的数据查询出来,然后使用insert into ... select 迁移到我们的新表中。话不多说,我们直接上sql:

SELECT 
    T1.id,
    SUBSTRING_INDEX( SUBSTRING_INDEX( T1.pages, ',', T2.help_topic_id + 1 ), ',',- 1 ) AS page 
FROM
    bus_mark_info T1
    JOIN mysql.help_topic T2 ON T2.help_topic_id < ( length( T1.pages )- length( REPLACE ( T1.pages, ',', '' ))+ 1 ) 
WHERE
    T1.pages IS NOT NULL 
ORDER BY
    T1.id,
    T2.help_topic_id

在这个sql中,我们使用了mysql 的help_topic表,这个表存储的是各种注释、地址等帮助信息,内容如下:
_20240402222508.jpg

这个表有一个特性,就是它有从0开始自增为1的id属性--help_topic_id 并且 拥有固定数量(701)的数据。

  • 关联数据数量

原始的bus_mark_info表中的每条数据,在与help_topic表关联后会生成多条新数据。具体来说,对于bus_mark_info表中的每条记录,我们期望生成的关联数据数量应该等于该记录中pages字段中逗号的数量加1。例如,如果某条数据的pages字段的取值为page1,page2,page3,那么我们应该生成三条关联数据。因此,我们的关联条件应该是T2.help_topic_id < (length(T1.pages) - length(REPLACE(T1.pages, ',', '')) + 1)

  • 正确分割字段

一旦确保了正确的关联数据数量,我们需要根据help_topic_id的值来截取我们的数据。例如,当help_topic_id为0时,我们应该取pages字段中第一个逗号之前的值;当help_topic_id为1时,我们应该取pages字段中第一个逗号和第二个逗号之间的值,依此类推。为实现这一目标,我们将使用两个SUBSTRING_INDEX函数来进行数据截取。首先,我们将截取从开始位置到help_topic_id+1个逗号之前的部分,然后再截取该部分中最后一个逗号之后的部分,即SUBSTRING_INDEX( SUBSTRING_INDEX( T1.pages, ',', T2.help_topic_id + 1 ), ',',- 1 )。通过这样的处理,我们便成功地利用help_topic_id和SUBSTRING_INDEX函数完成了数据的分割。

  • 注意事项

当然,我们使用help_topic是因为他的help_topic_id是从0开始,每次递增1的,我们也可以使用有次特性的别的表或者数据代替。
help_topic_id最大值为700,也就是说我们这个sql只能处理pages最多有701个页面连接的数据,如果有些pages字段分割之后的数量大于701,我们则需要使用别的表来替代。

如果有家人对SUBSTRING_INDEX函数和insert into ... select不太熟悉的话可以翻阅下我们历史的文章,有专门介绍过。

迁移数据sql

迁移数据的sql如下:

INSERT INTO bus_pages ( mark_id, page ) SELECT
T1.id,
SUBSTRING_INDEX( SUBSTRING_INDEX( T1.pages, ',', T2.help_topic_id + 1 ), ',',- 1 ) AS page 
FROM
    bus_mark_info T1
    JOIN mysql.help_topic T2 ON T2.help_topic_id < ( length( T1.pages )- length( REPLACE ( T1.pages, ',', '' ))+ 1 ) 
WHERE
    T1.pages IS NOT NULL 
ORDER BY
    T1.id,
    T2.help_topic_id

执行后数据表如下:

_20240402230223.jpg

总结

在实际开发中,当需要对包含多个字段连接符的数据进行查询与迁移时,可以使用SQL中的SUBSTRING_INDEX函数结合一些辅助表的特性进行数据分割和迁移。通过合理的SQL编写,可以有效处理数据关联与拆分,达到迁移数据的目的。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
安全 关系型数据库 MySQL
如何将数据从MySQL同步到其他系统
【10月更文挑战第17天】如何将数据从MySQL同步到其他系统
322 0
|
14天前
|
存储 关系型数据库 MySQL
mysql怎么查询longblob类型数据的大小
通过本文的介绍,希望您能深入理解如何查询MySQL中 `LONG BLOB`类型数据的大小,并结合优化技术提升查询性能,以满足实际业务需求。
52 6
|
1月前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
153 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
26天前
|
SQL 关系型数据库 MySQL
mysql分页读取数据重复问题
在服务端开发中,与MySQL数据库进行数据交互时,常因数据量大、网络延迟等因素需分页读取数据。文章介绍了使用`limit`和`offset`参数实现分页的方法,并针对分页过程中可能出现的数据重复问题进行了详细分析,提出了利用时间戳或确保排序规则绝对性等解决方案。
|
1月前
|
关系型数据库 MySQL 数据库
GBase 数据库如何像MYSQL一样存放多行数据
GBase 数据库如何像MYSQL一样存放多行数据
|
1月前
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
在项目中,为了解决Redis与Mysql的数据一致性问题,我们采用了多种策略:对于低一致性要求的数据,不做特别处理;时效性数据通过设置缓存过期时间来减少不一致风险;高一致性但时效性要求不高的数据,利用MQ异步同步确保最终一致性;而对一致性和时效性都有高要求的数据,则采用分布式事务(如Seata TCC模式)来保障。
68 14
|
1月前
|
分布式计算 关系型数据库 MySQL
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
57 8
|
1月前
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
67 9
|
2月前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
195 6
|
1月前
|
SQL 关系型数据库 MySQL
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
53 1