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

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS AI 助手,专业版
简介: 在开发中,遇到逗号分隔字段的处理是常见问题。本文通过一个实际场景展示了如何改造数据存储:从单一字段存储多个页面(如`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编写,可以有效处理数据关联与拆分,达到迁移数据的目的。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
10月前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
8月前
|
SQL 人工智能 关系型数据库
如何实现MySQL百万级数据的查询?
本文探讨了在MySQL中对百万级数据进行排序分页查询的优化策略。面对五百万条数据,传统的浅分页和深分页查询效率较低,尤其深分页因偏移量大导致性能显著下降。通过为排序字段添加索引、使用联合索引、手动回表等方法,有效提升了查询速度。最终建议根据业务需求选择合适方案:浅分页可加单列索引,深分页推荐联合索引或子查询优化,同时结合前端传递最后一条数据ID的方式实现高效翻页。
433 0
|
7月前
|
存储 关系型数据库 MySQL
在CentOS 8.x上安装Percona Xtrabackup工具备份MySQL数据步骤。
以上就是在CentOS8.x上通过Perconaxtabbackup工具对Mysql进行高效率、高可靠性、无锁定影响地实现在线快速全量及增加式数据库资料保存与恢复流程。通过以上流程可以有效地将Mysql相关资料按需求完成定期或不定期地保存与灾难恢复需求。
570 10
|
8月前
|
SQL 存储 缓存
MySQL 如何高效可靠处理持久化数据
本文详细解析了 MySQL 的 SQL 执行流程、crash-safe 机制及性能优化策略。内容涵盖连接器、分析器、优化器、执行器与存储引擎的工作原理,深入探讨 redolog 与 binlog 的两阶段提交机制,并分析日志策略、组提交、脏页刷盘等关键性能优化手段,帮助提升数据库稳定性与执行效率。
216 0
|
11月前
|
关系型数据库 MySQL Linux
在Linux环境下备份Docker中的MySQL数据并传输到其他服务器以实现数据级别的容灾
以上就是在Linux环境下备份Docker中的MySQL数据并传输到其他服务器以实现数据级别的容灾的步骤。这个过程就像是一场接力赛,数据从MySQL数据库中接力棒一样传递到备份文件,再从备份文件传递到其他服务器,最后再传递回MySQL数据库。这样,即使在灾难发生时,我们也可以快速恢复数据,保证业务的正常运行。
514 28
|
9月前
|
关系型数据库 MySQL
MySQL数据表添加字段(三种方式)
本文解析了数据表的基本概念及字段添加方法。在数据表中,字段是纵向列结构,记录为横向行数据。MySQL通过`ALTER TABLE`指令支持三种字段添加方式:1) 末尾追加字段,直接使用`ADD`语句;2) 首列插入字段,通过`FIRST`关键字实现;3) 指定位置插入字段,利用`AFTER`指定目标字段。文内结合`student`表实例详细演示了每种方法的操作步骤与结构验证,便于理解与实践。
|
Java 关系型数据库 MySQL
SpringBoot 通过集成 Flink CDC 来实时追踪 MySql 数据变动
通过详细的步骤和示例代码,您可以在 SpringBoot 项目中成功集成 Flink CDC,并实时追踪 MySQL 数据库的变动。
3136 45
|
存储 SQL 关系型数据库
【YashanDB知识库】MySQL迁移至崖山char类型数据自动补空格问题
**简介**:在MySQL迁移到崖山环境时,若字段类型为char(2),而应用存储的数据仅为&#39;0&#39;或&#39;1&#39;,查询时崖山会自动补空格。原因是mysql的sql_mode可能启用了PAD_CHAR_TO_FULL_LENGTH模式,导致保留CHAR类型尾随空格。解决方法是与应用确认数据需求,可将崖山环境中的char类型改为varchar类型以规避补空格问题,适用于所有版本。
|
10月前
|
存储 SQL 缓存
mysql数据引擎有哪些
MySQL 提供了多种存储引擎,每种引擎都有其独特的特点和适用场景。以下是一些常见的 MySQL 存储引擎及其特点:
273 0
|
12月前
|
SQL 关系型数据库 MySQL
【YashanDB知识库】字符集latin1的MySQL中文数据如何迁移到YashanDB
本文探讨了在使用YMP 23.2.1.3迁移MySQL Server字符集为latin1的中文数据至YashanDB时出现乱码的问题。问题根源在于MySQL latin1字符集存放的是实际utf8编码的数据,而YMP尚未支持此类场景。文章提供了两种解决方法:一是通过DBeaver直接迁移表数据;二是将MySQL表数据转换为Insert语句后手动插入YashanDB。同时指出,这两种方法适合单张表迁移,多表迁移可能存在兼容性问题,建议对问题表单独处理。
【YashanDB知识库】字符集latin1的MySQL中文数据如何迁移到YashanDB

推荐镜像

更多