行列转换是数据库查询中高频出现的需求,主要包含行转列和列转行两种场景,不同数据库的实现语法各有区别,掌握多种写法能适配更多开发环境。

一、行转列常见实现方式
1. 通用SQL写法:case when配合聚合函数
这种方式所有支持标准SQL的数据库都可以使用,核心逻辑是用case_when判断行数据的类别,再用聚合函数汇总对应的值。
假设我们有学生成绩表student_score,结构如下:
| student_name | subject | score |
|---|---|---|
| 张三 | 语文 | 90 |
| 张三 | 数学 | 85 |
| 李四 | 语文 | 88 |
| 李四 | 数学 | 92 |
需要将学科作为列,展示每个学生的语文和数学成绩,通用SQL写法如下:
SELECT
student_name,
MAX(CASE WHEN subject = '语文' THEN score ELSE 0 END) AS 语文,
MAX(CASE WHEN subject = '数学' THEN score ELSE 0 END) AS 数学
FROM student_score
GROUP BY student_name;
2. Oracle原生pivot语法
Oracle 11g及以上版本支持pivot关键字,语法更简洁,不需要手动写多个case_when。
SELECT *
FROM student_score
PIVOT (
MAX(score) -- 聚合函数,处理重复值
FOR subject IN ('语文' AS 语文, '数学' AS 数学) -- 指定要转为列的字段值
);
3. SQL Server原生pivot语法
SQL Server同样支持pivot关键字,语法和Oracle类似,只需要调整表名和字段引用方式。
SELECT student_name, 语文, 数学
FROM student_score
PIVOT (
MAX(score)
FOR subject IN (语文, 数学)
) AS pivot_table;
4. MySQL行转列实现
MySQL没有原生pivot语法,除了使用通用的case_when方式,也可以用动态SQL生成行转列语句,适配不确定的列名场景。
-- 动态生成行转列SQL,避免手动枚举所有学科
SET @sql = NULL;
SELECT GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(CASE WHEN subject = ''',
subject,
''' THEN score END) AS ''',
subject, ''''
)
) INTO @sql
FROM student_score;
SET @sql = CONCAT('SELECT student_name, ', @sql, ' FROM student_score GROUP BY student_name');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
二、列转行常见实现方式
1. 通用SQL写法:union all拼接结果
列转行是把多列数据拆分为多行,通用方式是用union all把每个列的查询结果拼接起来。
假设我们有转换后的成绩表student_score_pivot:
| student_name | 语文 | 数学 |
|---|---|---|
| 张三 | 90 | 85 |
| 李四 | 88 | 92 |
需要转回行存储的格式,通用SQL写法如下:
SELECT student_name, '语文' AS subject, 语文 AS score FROM student_score_pivot UNION ALL SELECT student_name, '数学' AS subject, 数学 AS score FROM student_score_pivot ORDER BY student_name, subject;
2. Oracle原生unpivot语法
Oracle支持unpivot关键字,直接指定要转换的列即可完成列转行。
SELECT student_name, subject, score
FROM student_score_pivot
UNPIVOT (
score -- 转换后的值列名
FOR subject IN (语文, 数学) -- 要转为行的列名
);
3. SQL Server原生unpivot语法
SQL Server的unpivot语法和Oracle类似,使用方式如下:
SELECT student_name, subject, score
FROM student_score_pivot
UNPIVOT (
score FOR subject IN (语文, 数学)
) AS unpivot_table;
三、注意事项
- 行转列时如果有多个相同分组下的重复值,需要根据业务需求选择合适的聚合函数,比如求和用
SUM,取最大值用MAX。 - 使用
pivot或unpivot时,要注意数据库版本是否支持,低版本数据库只能使用通用写法。 - 动态行列转换场景优先选择动态SQL实现,避免硬编码列名,减少后续维护成本。