MySQL:如何在SELECT子句中使用多查询实现行转列?
解决行转列(将month转为m1-m4列)的SQL问题
嘿,别着急,你遇到的是典型的**行转列(Pivot)**问题,我来一步步帮你搞定!
首先先明确你的表和数据:
你的aaa表数据整理后如下:
year | month | amount -----|-------|------- 1991 | 1 | 1.1 1991 | 2 | 1.2 1991 | 3 | 1.3 1991 | 4 | 1.4 1992 | 1 | 2.1 1992 | 2 | 2.2 1992 | 3 | 2.3 1993 | 4 | 2.4 -- 注:原始数据里1993年只有4月的记录
你期望的结果是把每个month的值转为单独的列(m1到m4),按year分组展示。
先说说你之前尝试的SQL问题
- 第一个SQL的问题:子查询
SELECT amount FROM aaa WHERE month=1没有关联外层的year,会返回所有month=1的记录,当有多个值时就会报错“子查询返回多于一行”。 - 第二个SQL虽然关联了
year,但没有用聚合函数,而且GROUP BY year后,外层表的非聚合字段不符合多数数据库的语法规则(比如MySQL的ONLY_FULL_GROUP_BY模式),会直接报错或返回不可预期的结果。
正确的通用解法(适用于绝大多数数据库:MySQL、PostgreSQL、SQLite等)
我们可以用CASE WHEN配合聚合函数(比如MAX(),因为每个year+month组合只有一条数据,MAX和SUM效果一致)来实现行转列:
SELECT year, MAX(CASE WHEN month = 1 THEN amount END) AS m1, MAX(CASE WHEN month = 2 THEN amount END) AS m2, MAX(CASE WHEN month = 3 THEN amount END) AS m3, MAX(CASE WHEN month = 4 THEN amount END) AS m4 FROM aaa GROUP BY year ORDER BY year;
逻辑解释:
CASE WHEN month = 1 THEN amount END:只保留当前行month=1时的amount值,其他情况为NULLMAX():按year分组后,提取每个分组内对应month的非NULL值(每个year对应一个month的记录唯一,MAX会精准拿到目标值,NULL会被忽略)GROUP BY year:按年份分组,把同一年的所有行合并成一行ORDER BY year:让结果按年份排序,和你期望的格式对齐
如果你用的是支持PIVOT语法的数据库(比如SQL Server、Oracle)
也可以用更简洁的PIVOT语法,比如SQL Server的写法:
SELECT year, m1, m2, m3, m4 FROM aaa PIVOT ( MAX(amount) FOR month IN ([1] AS m1, [2] AS m2, [3] AS m3, [4] AS m4) ) AS PivotTable ORDER BY year;
最终执行结果
执行通用SQL后,会得到如下结果(和你的期望基本一致,修正了原始数据的笔误):
year | m1 | m2 | m3 | m4 -----|-----|-----|-----|----- 1991 | 1.1 | 1.2 | 1.3 | 1.4 1992 | 2.1 | 2.2 | 2.3 | NULL 1993 | NULL| NULL| NULL| 2.4
内容的提问来源于stack exchange,提问作者Sean.H
相关产品推荐
相关产品推荐

