mysql系列——行转列,列转行(十一)
行转列
例如:把图1转换成图2结果展示
图1如下:
图2如下:
建表语句:
1 2 3 4 5 6 7 8 9 | DROP TABLE IF EXISTS tb_score; CREATE TABLE tb_score( id INT( 11 ) NOT NULL auto_increment, userid VARCHAR( 20 ) NOT NULL COMMENT '用户id' , subject VARCHAR( 20 ) COMMENT '科目' , score DOUBLE COMMENT '成绩' , PRIMARY KEY(id) )ENGINE = INNODB DEFAULT CHARSET = utf8; |
插入数据:
1 2 3 4 5 6 7 8 9 10 | INSERT INTO tb_score(userid,subject,score) VALUES ( '001' , '语文' , 90 ); INSERT INTO tb_score(userid,subject,score) VALUES ( '001' , '数学' , 92 ); INSERT INTO tb_score(userid,subject,score) VALUES ( '001' , '英语' , 80 ); INSERT INTO tb_score(userid,subject,score) VALUES ( '002' , '语文' , 88 ); INSERT INTO tb_score(userid,subject,score) VALUES ( '002' , '数学' , 90 ); INSERT INTO tb_score(userid,subject,score) VALUES ( '002' , '英语' , 75.5 ); INSERT INTO tb_score(userid,subject,score) VALUES ( '003' , '语文' , 70 ); INSERT INTO tb_score(userid,subject,score) VALUES ( '003' , '数学' , 85 ); INSERT INTO tb_score(userid,subject,score) VALUES ( '003' , '英语' , 90 ); INSERT INTO tb_score(userid,subject,score) VALUES ( '003' , '政治' , 82 ); |
1、使用case...when....then 进行行转列
1 2 3 4 5 6 7 | SELECT userid, SUM(CASE `subject` WHEN '语文' THEN score ELSE 0 END) as '语文' , SUM(CASE `subject` WHEN '数学' THEN score ELSE 0 END) as '数学' , SUM(CASE `subject` WHEN '英语' THEN score ELSE 0 END) as '英语' , SUM(CASE `subject` WHEN '政治' THEN score ELSE 0 END) as '政治' FROM tb_score GROUP BY userid |
2、使用IF() 进行行转列:
1 2 3 4 5 6 7 | SELECT userid, SUM(IF(`subject`= '语文' ,score, 0 )) as '语文' , SUM(IF(`subject`= '数学' ,score, 0 )) as '数学' , SUM(IF(`subject`= '英语' ,score, 0 )) as '英语' , SUM(IF(`subject`= '政治' ,score, 0 )) as '政治' FROM tb_score GROUP BY userid |
注意点:
(1)sum() 是为了能够使用GROUP BY根据userid进行分组,因为每一个userid对应的subject="语文"的记录只有一条,所以SUM() 的值就等于对应那一条记录的score的值。
假如userid ='001' and subject='语文' 的记录有两条,则此时SUM() 的值将会是这两条记录的和,同理,使用Max()的值将会是这两条记录里面值最大的一个。但是正常情况下,一个user对应一个subject只有一个分数,因此可以使用SUM()、MAX()、MIN()、AVG()等聚合函数都可以达到行转列的效果。
(2)IF(subject='语文',score,0) 作为条件,即对所有subject='语文'的记录的score字段进行SUM()、MAX()、MIN()、AVG()操作,如果score没有值则默认为0。
列转行
上面图2转成图1
建表语句:
1 2 3 4 5 6 7 8 9 | CREATE TABLE tb_score1( id INT( 11 ) NOT NULL auto_increment, userid VARCHAR( 20 ) NOT NULL COMMENT '用户id' , cn_score DOUBLE COMMENT '语文成绩' , math_score DOUBLE COMMENT '数学成绩' , en_score DOUBLE COMMENT '英语成绩' , po_score DOUBLE COMMENT '政治成绩' , PRIMARY KEY(id) )ENGINE = INNODB DEFAULT CHARSET = utf8; |
插入数据:
1 2 3 | INSERT INTO tb_score1(userid,cn_score,math_score,en_score,po_score) VALUES ( '001' , 90 , 92 , 80 , 0 ); INSERT INTO tb_score1(userid,cn_score,math_score,en_score,po_score) VALUES ( '002' , 88 , 90 , 75.5 , 0 ); INSERT INTO tb_score1(userid,cn_score,math_score,en_score,po_score) VALUES ( '003' , 70 , 85 , 90 , 82 ); |
本质是将userid的每个科目分数分散成一条记录显示出来。
1 2 3 4 5 6 7 8 | SELECT userid, '语文' AS course,cn_score AS score FROM tb_score1 UNION ALL SELECT userid, '数学' AS course,math_score AS score FROM tb_score1 UNION ALL SELECT userid, '英语' AS course,en_score AS score FROM tb_score1 UNION ALL SELECT userid, '政治' AS course,po_score AS score FROM tb_score1 ORDER BY userid |
这里将每个userid对应的多个科目的成绩查出来,通过UNION ALL将结果集加起来,达到上图的效果。
附:UNION与UNION ALL的区别(摘):
1.对重复结果的处理:UNION会去掉重复记录,UNION ALL不会;
2.对排序的处理:UNION会排序,UNION ALL只是简单地将两个结果集合并;
3.效率方面的区别:因为UNION 会做去重和排序处理,因此效率比UNION ALL慢很多;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
2021-08-12 Shiro权限管理框架(三):Shiro中权限过滤器的初始化流程和实现原理