Mysql-列转行(字段中多个值转换为多行)

本文介绍了如何使用SQL查询将字符串按逗号分隔并转换为多行,结合自增ID表实现数据列转行的效果。通过示例展示了当ID最小值为1和0时的不同SQL写法,适用于处理包含逗号分隔信息的数据记录。

1、借助一张id连续的mysql表,并使得存储的id值尽可能大于字段里存的值个数

如果使用表自增id,则id默认从1开始:

2、拼写sql

t_auto_id 表中 id最小值为1:

SELECT
a.id,
a.name,
SUBSTRING_INDEX( SUBSTRING_INDEX( a.address, ',', b.id ), ',', - 1 ) AS address
FROM
`t_user` AS a
JOIN t_auto_id AS b ON b.id <= ( length( a.address ) - length( REPLACE ( a.address, ',', '' ) ) + 1 )

原数据:

列转行之后效果:

注:如果t_auto_id 表中 id最小值为0,则需要调整sql为:

SELECT
a.id,
a.name,
SUBSTRING_INDEX( SUBSTRING_INDEX( a.address, ',', b.id + 1 ), ',', -1 ) AS address
FROM
`t_user` AS a
JOIN t_auto_id AS b ON b.id < ( length( a.address ) - length( REPLACE ( a.address, ',', '' ) ) + 1 )


 

<think>我们正在讨论的是DB2中如何将一行多数据转换多行数据(转行)。根据用户的问题和之前的回答,用户已经了解两种方法:UNPIVOT和TABLE函数结合VALUES子句。现在用户再次询问一行多多行的方法,我们可以再详细说明这两种方法,并参考站内引用提供其他可能的思路(如XML方式,但注意XML方式通常用于多行转一行,而不是转行,所以需要谨慎参考)。 根据引用[5]中提供的表结构(water_quality表),它有很多JCXM_开头的,这正是一行多的结构。我们可以以此为例进行说明。 目标:将多个JCXM_(如JCXM_PH, JCXM_RYL等)转换多行,每行包含原行的一些标识字段(如NF, YF, HL, DMMC)以及转换后的两个新:检测项目名称(如PH)和检测。 方法1:使用UNPIVOT(推荐) 步骤: 1. 选择需要保留的标识(不参与转行)。 2. 使用UNPIVOT将多个转换为两:一存储原名(去除前缀),另一存储对应的。 示例代码(基于引用[5]的表): ```sql SELECT NF, YF, HL, DMMC, -- 使用REPLACE函数去除名前缀,只保留项目名称 REPLACE(检测项目, 'JCXM_', '') AS 检测项目, 检测 FROM water_quality UNPIVOT ( 检测 FOR 检测项目 IN ( JCXM_PH, JCXM_RYL, JCXM_GMSYZS, JCXM_SHXYL, JCXM_AD, JCXM_SYL, JCXM_HFF, JCXM_GONG, JCXM_QIAN, JCXM_GE, JCXM_YLZBMHXJ, JCXM_LUO, JCXM_FHW, JCXM_ZL, JCXM_QHW, JCXM_LHW, JCXM_SHEN, JCXM_HXXYL, JCXM_TONG, JCXM_XIN, JCXM_XI ) ) AS unpvt; ``` 方法2:使用TABLE函数和VALUES子句(通用方法) 步骤: 1. 使用内联表函数(TABLE)和VALUES子句为每一生成一行。 2. 通过CROSS JOIN(或INNER JOIN ON 1=1)将原表的每一行与生成的表连接。 示例代码: ```sql SELECT wq.NF, wq.YF, wq.HL, wq.DMMC, -- 同样去除前缀 REPLACE(t.检测项目, 'JCXM_', '') AS 检测项目, t.检测 FROM water_quality wq CROSS JOIN TABLE ( VALUES ('JCXM_PH', wq.JCXM_PH), ('JCXM_RYL', wq.JCXM_RYL), ('JCXM_GMSYZS', wq.JCXM_GMSYZS), ('JCXM_SHXYL', wq.JCXM_SHXYL), ('JCXM_AD', wq.JCXM_AD), ('JCXM_SYL', wq.JCXM_SYL), ('JCXM_HFF', wq.JCXM_HFF), ('JCXM_GONG', wq.JCXM_GONG), ('JCXM_QIAN', wq.JCXM_QIAN), ('JCXM_GE', wq.JCXM_GE), ('JCXM_YLZBMHXJ', wq.JCXM_YLZBMHXJ), ('JCXM_LUO', wq.JCXM_LUO), ('JCXM_FHW', wq.JCXM_FHW), ('JCXM_ZL', wq.JCXM_ZL), ('JCXM_QHW', wq.JCXM_QHW), ('JCXM_LHW', wq.JCXM_LHW), ('JCXM_SHEN', wq.JCXM_SHEN), ('JCXM_HXXYL', wq.JCXM_HXXYL), ('JCXM_TONG', wq.JCXM_TONG), ('JCXM_XIN', wq.JCXM_XIN), ('JCXM_XI', wq.JCXM_XI) ) AS t(检测项目, 检测); ``` 注意:如果原表中某些可能为NULL,那么转换后的行中也会包含这些NULL。如果不想包含NULL,可以在外层添加WHERE条件,例如:`WHERE t.检测 IS NOT NULL`。 另外,参考引用[1]中提到了使用XML方式实现多行转一行,但这里我们是一行多多行,所以XML方式不适用。引用[2]是关于行转(PIVOT)的,与本次需求相反。引用[4]是关于将逗号分隔的字符串拆分成多行的,也不适用于当前场景。引用[3]是关于MySQL的基础操作,与DB2无关。 因此,我们主要采用上述两种方法。 总结: - 如果DB2版本支持UNPIVOT(DB2 9.7及以上),则推荐使用UNPIVOT,因为它更简洁且性能通常更好。 - 如果版本较低或需要动态生成,则使用TABLE函数与VALUES子句。 最后,我们生成相关问题。</think>### DB2一行多多行数据实现方法 在DB2中,将一行多数据转换多行数据(转行)是常见的数据转换需求,以下是两种高效实现方法,结合您的表结构示例(`water_quality`表)进行说明: #### 方法1: 使用UNPIVOT操作(推荐) **适用场景**:DB2 9.7及以上版本,固定数的转换 ```sql SELECT NF, YF, HL, DMMC, REPLACE(REPLACE(检测项目, 'JCXM_', ''), '_', ' ') AS 检测项目, -- 清理名 检测 FROM water_quality UNPIVOT ( 检测 FOR 检测项目 IN ( JCXM_PH, JCXM_RYL, JCXM_GMSYZS, JCXM_SHXYL, JCXM_AD, JCXM_SYL, JCXM_HFF, JCXM_GONG, JCXM_QIAN, JCXM_GE, JCXM_YLZBMHXJ, JCXM_LUO, JCXM_FHW, JCXM_ZL, JCXM_QHW, JCXM_LHW, JCXM_SHEN, JCXM_HXXYL, JCXM_TONG, JCXM_XIN, JCXM_XI ) ) AS unpvt WHERE NF = '2023'; -- 示例过滤条件 ``` **关键点**: 1. `UNPIVOT`子句将21个检测项目转换为两:`检测项目`(原始名)和`检测` 2. 使用`REPLACE`清理名(如将"JCXM_PH"转为"PH") 3. 保留原表标识字段(NF, YF等) 4. **输出效果**: ``` NF | YF | HL | DMMC | 检测项目 | 检测 -----|----|-----|------|---------|------- 2023 | 01 | HL1 | 地点1| PH | 6.8 2023 | 01 | HL1 | 地点1| RYL | 0.2 ...(每个检测项目生成一行) ``` #### 方法2: 使用VALUES子句+横向连接(兼容所有版本) **适用场景**:低版本DB2或动态处理 ```sql SELECT wq.NF, wq.YF, wq.HL, wq.DMMC, REPLACE(REPLACE(t.jcxm, 'JCXM_', ''), '_', ' ') AS 检测项目, t.jcz FROM water_quality wq, TABLE ( VALUES ('JCXM_PH', wq.JCXM_PH), ('JCXM_RYL', wq.JCXM_RYL), ('JCXM_GMSYZS', wq.JCXM_GMSYZS), -- 其他18个检测项目... ('JCXM_XI', wq.JCXM_XI) ) AS t(jcxm, jcz) WHERE wq.NF = '2023'; ``` **关键点**: 1. 通过`TABLE(VALUES...)`创建虚拟表,每行对应一个键对 2. 横向连接(隐式`CROSS JOIN`)确保每行原数据生成多行 3. 相同的数据清洗逻辑处理名 #### 性能优化建议 1. **索引优化**:在过滤(如`NF`, `YF`)上创建索引 ```sql CREATE INDEX idx_nf_yf ON water_quality(NF, YF); ``` 2. **减少转换数**:只选择必要的检测项目 3. **分区处理**:对大表按时间(如`NF`)进行表分区 4. **数据类型**:确保所有检测类型兼容(如都是`VARCHAR(50)`) #### 实际应用场景 1. **水质报表转换**:将横向存储的检测项目转为纵向记录[^5] 2. **绩效考核**:多考核指标转键对(存款考核→业务量考核)[^2] 3. **物联网数据**:设备多传感器读数转时间序存储 > **注意**:当名需要动态生成时,可结合存储过程动态构建SQL,但需注意SQL注入风险。
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值