不使用union实现Mysql 列转行

最近工作上用到了 mysql列转行,网上找了一堆大多数都是行转列的方法,对于列转行这块,仅找到了union这一种方式,偏偏工作环境的数据库版本较低不支持临时表,使用union方式写起来又过于笨重,所以这里记录下使用union及不使用union的列转行解决办法

注:未比较两种方式执行效率

测试数据:

CREATE TABLE `test` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `chinese` int DEFAULT NULL,
  `math` int DEFAULT NULL,
  `english` int DEFAULT NULL,
  `wuli` int DEFAULT NULL,
  `huaxue` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

INSERT INTO test.test (id, name, chinese, math, english, wuli, huaxue) VALUES(1, '张三', 110, 120, 85, NULL, NULL);
INSERT INTO test.test (id, name, chinese, math, english, wuli, huaxue) VALUES(2, '李四', 130, 88, 89, NULL, NULL);
INSERT INTO test.test (id, name, chinese, math, english, wuli, huaxue) VALUES(3, '王五', 93, 124, 87, 98, 67);

基本的union 列转行写法:

-- 第一种使用union实现列传行
select name,'语文' as course, chinese as 'score' from test union 
select name,'数学' as course, math as 'score' from test union 
select name,'英语' as course, english as 'score' from test union 
select name,'物理' as course, wuli as 'score' from test union 
select name,'化学' as course, huaxue as 'score' from test order by name asc

实现效果:
在这里插入图片描述

不使用union 列转行写法:

不用union的方式实现思路:

列转行主要核心就是一条数据转多条,如果不多次查询,又想实现列转行,就需要先对数据按照我们的查询需求进行条数扩充;同时为了保证扩充结果可以满足我们后续提取数据的需要,所以扩充的同时需要往数据中填充字段名用于字段提取。

-- 借助系统表(或自己构造临时数据)用join 扩增数据,然后使用case when 实现列转行,获取想要的结果集。
select  
	b.name,
	a.COLUMN_NAME as 科目,
	case a.COLUMN_NAME when 'chinese' then b.chinese when 'math' then b.math
	     when 'english' then b.english when 'wuli' then b.wuli  when 'huaxue' then b.huaxue end as 成绩
from 
-- 借助系统表获取字段清单,添加自定义joinid用于数据关联
	(select  COLUMN_NAME ,'aa' as joinid from  information_schema.`COLUMNS` c  where TABLE_NAME ='test' and column_name not in ('id','name')) a 
-- 使用自定义joinid  join  获取笛卡尔积结果集
	left  join 
-- 查询源表,添加自定义joinid用于数据关联
	(select *,'aa' as joinid from test t ) b 
	on a.joinid=b.joinid order by b.name
过程展示:
通过系统表获取字段名,同时补充自定义关联列:

在这里插入图片描述

使用join关联字段名表和数据表,完成数据构造:

在这里插入图片描述

使用case when 提取想要的数据,达到列转行的目标:

在这里插入图片描述

### MySQL实现转行功能 在 MySQL 中,可以使用 `UNION ALL` 或者 `GROUP_CONCAT()` 函数来模拟转行的效果。对于更复杂的场景,通常会结合存储过程或临时表来完成转换。 #### 使用 UNION ALL 实现简单转行 当数据量较小且结构固定时,可以直接通过 `UNION ALL` 来拼接多条记录: ```sql SELECT 'ColumnA' AS source_column, ColumnA AS value FROM table_name UNION ALL SELECT 'ColumnB', ColumnB FROM table_name; ``` 这种方法适用于少量的情况,并能保持较好的性能[^1]。 #### 利用 GROUP_CONCAT 和 SUBSTRING_INDEX 进行复杂处理 如果需要处理更多动态变化的数据,则可以通过组合多个聚合函数达到目的: ```sql SET SESSION group_concat_max_len = 1000000; SELECT id, SUBSTRING_INDEX(GROUP_CONCAT(column_values SEPARATOR ','), ',', n.n) AS single_value FROM ( SELECT t.*, CONCAT_WS(',', col1, col2, col3...) AS column_values FROM your_table t ) combined_data JOIN numbers n ON CHAR_LENGTH(combined_data.column_values) -CHAR_LENGTH(REPLACE(combined_data.column_values,',','')) >= n.n-1 GROUP BY id, n.n; ``` 此查询假设存在一个名为 `numbers` 的辅助表用于生成序号 `n`,可以根据实际需求调整逻辑[^2]。 #### 数据分割方法 针对特定字段内容的拆分操作,在 SQL 查询语句内部可借助字符串处理函数如 `SUBSTRING_INDEX()` 完成基本切割工作;而对于更加灵活的需求则推荐采用编程语言编写外部脚本配合数据库交互的方式解决。 例如要按照逗号分隔符切分某中的值并将其作为独立行返回,可以用如下方式: ```sql WITH RECURSIVE cte AS( SELECT id, TRIM(SUBSTRING_INDEX(value_list, ',', 1)) item, CASE WHEN LOCATE(',', value_list)>0 THEN INSERT(value_list, 1, LOCATE(',', value_list)+1,'') ELSE '' END rest FROM mytable WHERE value_list IS NOT NULL AND LENGTH(TRIM(value_list))>0 UNION ALL SELECT id,TRIM(SUBSTRING_INDEX(rest, ',', 1)), CASE WHEN LOCATE(',',rest)>0 THEN INSERT(rest , 1,LOCATE(',',rest )+1,'') ELSE '' END FROM cte WHERE rest !='' ) SELECT DISTINCT id,item FROM cte ORDER BY id; ``` 上述代码片段展示了如何利用递归公用表达式(CTE)迭代解析包含表形式数据的单个单元格,最终得到每项单独占据一行的结果集[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值