MySQL行列转换
实际应用中,会遇到需要把表的某些行转换成列,或者把列转换成行的情况。比如一张表在数据库中是这样的:
图1
但是,需要的结果可能是这样:
图2
这个时候就得行列转换了。
1.行转列的几种方法
1.1 case ... when ... then ... else ... end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | select uname,uid, -- 正常查询的字段 sum ( case when course = '英语' then score -- 需要转换的字段 else 0 end ) '英语' , sum ( case when course= '物理' then score else 0 end ) '物理' , sum ( case when course= '化学' then score else 0 end ) '化学' from course group by uid |
另一种写法:
1 2 3 4 | case course when '化学' then score else 0 end |
另外若省略‘else 0‘,则没有该课程的同学的分数会填充为null; sum替换成max结果一样。
1.2 if (`字段名1`=‘字段值’,,)
1 2 3 4 5 6 | select uname,uid, sum (if(`course`= '英语' ,score,0)) '英语' , sum (if(`course`= '物理' ,score,0)) '物理' , sum (if(`course`= '化学' ,score,0)) '化学' from course group by uname |
貌似比第一种方法简洁一些,所以下面的扩展是基于这种方法的~
以上两种转换方法结果相同,如图2。另外实际应用中还可能需要有总计的结果,如图3.
图3
total这一列简单,直接在之前的查询基础上加一个sum(score) 'total'即可;Total这一行则可以看成之前的查询不加group by而聚合成一行。因此可以看做是两个表组合到一起如图4和图5:
图4
图5
1.3 if (`字段名1`=‘字段值’,,) + union
把两个查询结果拼接到一起就是图3的样子了,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | select uid,uname, sum (if(`course`= '英语' ,score,0)) '英语' , sum (if(`course`= '物理' ,score,0)) '物理' , sum (if(`course`= '化学' ,score,0)) '化学' , sum (score) 'total' from course group by uname union select 'Total' , null , sum (if(`course`= '英语' ,score,0)) '英语' , sum (if(`course`= '物理' ,score,0)) '物理' , sum (if(`course`= '化学' ,score,0)) '化学' , sum (score) 'total' from course |
1.4 if (`字段名1`=‘字段值’,,) + IFNULL()+with rollup
这种方法效果同1.3,
1 2 3 4 5 6 7 8 | select ifnull(uid, 'Total' ) uid, uname, sum (if(`course`= '英语' ,score,0)) '英语' , sum (if(`course`= '物理' ,score,0)) '物理' , sum (if(`course`= '化学' ,score,0)) '化学' , sum (score) 'total' from course group by uid with ROLLUP |
比1.3简洁一些,效率应该也高一点。with rollup和group by配套使用,会在已有的查询结果上再多出一行,对结果再聚合成一行,即图5的那一行,若不是数字类型,则返回最下面一行的数据,最后一行分组的字段会显示null,因此在配合ifnull()就可以了。
有瑕疵,想把它变成 null,有待完善。
2.列转行
列转行刚好和行转列情况相反,即:
数据库中存储的是这样
图2
而我们需要这样的结果
图1
没有在创建新表,暂且把这个视图当成新表吧
1 2 3 4 5 6 7 8 9 10 11 12 13 | create view rtc as select ifnull(uid, 'Total' ) uid,uname, sum (if(`course`= '英语' ,score,0)) '英语' , sum (if(`course`= '物理' ,score,0)) '物理' , sum (if(`course`= '化学' ,score,0)) '化学' , sum (score) 'total' from course group by uid with ROLLUP -- 下面是列转行代码 select uid,uname, '英语' course,英语 score from rtc where uid <> 'Total' and 英语>0 union all select uid,uname, '物理' ,物理 from rtc where uid <> 'Total' and 物理>0 union all select uid,uname, '化学' ,化学 from rtc where uid <> 'Total' and 化学>0 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
2020-06-02 Mac安装Homebrew的正确姿势