SQL中的行转列操作指的是将表中原本按行存储的多个同类数据,转换为按列展示的结构,这种操作在生成统计报表、整理多维度数据时非常实用,核心实现方式就是结合CASE WHEN条件判断和聚合函数完成数据重组。

行转列的核心逻辑
行转列的本质是先通过CASE_WHEN对原始行的不同取值进行分类标记,再使用聚合函数对标记后的结果进行合并,最终将多行数据压缩为单行不同列的值。整个过程不需要改变原始表结构,仅通过查询语句就能得到目标结果。
CASE WHEN的作用
CASE_WHEN在这里用来判断原始行的某个字段值,当满足条件时返回对应的标识值,不满足时返回默认值,相当于给每一行数据打上分类标签。比如原始表中存储了不同科目的成绩,用CASE_WHEN可以判断当前行是语文、数学还是英语成绩,分别返回对应的分数或者空值。
聚合函数的作用
经过CASE_WHEN处理之后,同一个分组下会出现多行数据,每行对应不同分类的标签值,这时候使用MAX、SUM这类聚合函数,就能把同一个分组下的多个标签值合并成单个值,从而实现多行转单行的效果。
实战案例演示
假设我们有一张学生成绩表student_score,表结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| student_id | INT | 学生ID |
| subject | VARCHAR | 科目名称 |
| score | INT | 对应科目分数 |
表中部分原始数据如下:
| student_id | subject | score |
|---|---|---|
| 1 | 语文 | 85 |
| 1 | 数学 | 92 |
| 1 | 英语 | 88 |
| 2 | 语文 | 90 |
| 2 | 数学 | 87 |
| 2 | 英语 | 91 |
现在需要把这张表转换为每个学生一行,分别展示语文、数学、英语三科成绩的行转列结果,实现SQL如下:
-- 行转列查询语句
SELECT
student_id,
-- 判断科目为语文时返回分数,否则返回NULL
MAX(CASE WHEN subject = '语文' THEN score ELSE NULL END) AS 语文,
-- 判断科目为数学时返回分数,否则返回NULL
MAX(CASE WHEN subject = '数学' THEN score ELSE NULL END) AS 数学,
-- 判断科目为英语时返回分数,否则返回NULL
MAX(CASE WHEN subject = '英语' THEN score ELSE NULL END) AS 英语
FROM
student_score
-- 按学生ID分组,保证每个学生一行数据
GROUP BY
student_id
ORDER BY
student_id;
执行上述语句后,得到的结果如下:
| student_id | 语文 | 数学 | 英语 |
|---|---|---|---|
| 1 | 85 | 92 | 88 |
| 2 | 90 | 87 | 91 |
注意事项
- 聚合函数的选择:如果同一个分组同一个分类下只有一条数据,使用
MAX、MIN、SUM都可以得到正确结果;如果存在多条数据需要累加,就使用SUM函数。 - 分组字段的选择:
GROUP BY后面的字段是行转列后作为行的标识字段,需要根据业务需求正确选择,否则会出现数据错乱。 - ELSE默认值:
CASE_WHEN中ELSE建议返回NULL,这样聚合函数计算时会自动忽略空值,不会影响最终结果。
不同数据库的差异
上述写法是标准SQL,在MySQL、PostgreSQL、SQL Server等主流数据库中都可以正常运行。部分数据库提供了内置的行转列函数,比如Oracle的PIVOT、SQL Server的PIVOT,但使用CASE WHEN加聚合函数的方式兼容性更好,适合跨数据库场景使用。
如果业务中的转列字段值是动态的,无法提前在SQL中写死分类,也可以通过存储过程或者动态SQL的方式拼接CASE WHEN逻辑,实现动态行转列的效果。