SQL Server 行列互转实战:CASE WHEN 与 PIVOT/UNPIVOT 方法解析

Chloe
Chloe
发布时间:2026-10-13| 4人浏览过
原创

在数据库查询中,行转列(Pivot)与列转行(Unpivot)是处理报表数据时的常见需求。本文将对比两种主流实现方式:传统且兼容性强的 CASE ... END 聚合函数法,以及 SQL Server 2005 起支持的专用关键字 PIVOT 和 UNPIVOT。通过具体的学生成绩表案例,展示如何构建测试数据、编写转换语句并验证最终结果。

场景准备:测试数据结构

为了直观展示转换效果,我们首先需要构建一个典型的“长表”结构。假设有一个存储学生科目成绩的临时表 @t,其中每一行代表一名学生在某一科目的得分。这种结构便于录入,但不利于横向对比每位学生的所有成绩。

declare @t table
(StudentName nvarchar(20),
 Subject nvarchar(20),
 Score int)
 
Insert into @t (StudentName,Subject,Score) values ( '学生A', '中文', 80 );  
Insert into @t (StudentName,Subject,Score) values ( '学生A', '数学', 78 );  
Insert into @t (StudentName,Subject,Score) values ( '学生A', '英语', 92 );  
Insert into @t (StudentName,Subject,Score) values ( '学生B', '中文', 89 );  
Insert into @t (StudentName,Subject,Score) values ( '学生B', '数学', 87 );  
Insert into @t (StudentName,Subject,Score) values ( '学生B', '英语', 75 );  
Insert into @t (StudentName,Subject,Score) values ( '学生C', '中文', 92 );  
Insert into @t (StudentName,Subject,Score) values ( '学生C', '数学', 74 );  
Insert into @t (StudentName,Subject,Score) values ( '学生C', '英语', 65 );  
Insert into @t (StudentName,Subject,Score) values ( '学生D', '中文', 79 );  
Insert into @t (StudentName,Subject,Score) values ( '学生D', '数学', 83 );  
Insert into @t (StudentName,Subject,Score) values ( '学生D', '英语', 81 );  
Insert into @t (StudentName,Subject,Score) values ( '学生E', '中文', 73 );  
Insert into @t (StudentName,Subject,Score) values ( '学生E', '数学', 84 );  
Insert into @t (StudentName,Subject,Score) values ( '学生E', '英语', 93 );  
Insert into @t (StudentName,Subject,Score) values ( '学生F', '中文', 79 );  
Insert into @t (StudentName,Subject,Score) values ( '学生F', '数学', 86 );  
Insert into @t (StudentName,Subject,Score) values ( '学生F', '英语', 84 ); 

方法一:使用 CASE WHEN 聚合函数

这是最通用且兼容性最好的方法,适用于几乎所有支持 SQL 语法的数据库。其核心逻辑是利用 CASE 表达式判断当前行属于哪个科目,若匹配则返回分数,否则返回 0。最后通过聚合函数(如 SUM)按学生分组汇总。

第1步:编写行转列查询

  • 目的:将不同科目的成绩分散在不同的列中显示。
  • 关键参数:GROUP BY StudentName 确保每个学生只有一行输出。
  • 操作:对每个科目编写独立的 sum(case when ... then ... else 0 end) 字段。
select StudentName,
    sum(case when Subject = N'中文' then Score else 0 end) Chinese,
    sum(case when Subject = N'数学' then Score else 0 end) Math,
    sum(case when Subject = N'英语' then Score else 0 end) English
 from @t
 group by StudentName

第2步:验证输出结果

执行后,表格将从原来的多行记录(每名学生多条记录)变为单行记录(每名学生一条记录包含各科分数)。此方法优点是逻辑直观,缺点是如果科目动态增加或数量巨大,SQL 语句会变得冗长。

方法二:使用 PIVOT 关键字(SQL Server 2005+)

PIVOT 是 SQL Server 提供的专用行转列运算符,语法更加紧凑,专门用于此类透视操作。它要求源数据必须先经过子查询处理。

第1步:理解 PIVOT 语法结构

PIVOT 的基本骨架如下:


pivot(
    aggregate_function(value_column)
    for pivot_column
    in ()
)
AS alias
  • table_source:进行转换的数据源(通常是子查询)。
  • aggregate_function:使用的聚合函数,通常为 SUM、AVG 等。
  • value_column:需要被聚合的数值列(原表中的 Score)。
  • pivot_column:需要根据其唯一值来生成新列名的列(原表中的 Subject)。
  • in (...):明确指定要生成的目标列名列表。

第2步:执行行转列操作

  • 入口:直接对 @t 表或其子查询应用 PIVOT。
  • 动作:指定对 Score 求和,根据 Subject 的值生成 [中文], [英语], [数学] 列。
select StudentName,
    [Chinese] = [中文],
    [Math] = [数学],
    [English] = [英语]
 from
(select * from @t) t1
pivot (sum(Score) for Subject in([中文],[英语],[数学])) t2

注意:在 IN 子句中列出的顺序决定了结果集中新列的顺序。上述示例中特意调整了列名别名以符合英文习惯,实际使用中可直接引用生成的中文名列。

逆向操作:使用 UNPIVOT 列转行

如果之前通过 PIVOT 得到了宽表,可以使用 UNPIVOT 将其还原为原始的长表格式。这通常用于数据规范化或合并来自不同宽表的来源。

第1步:构建 UNPIVOT 查询

  • 目的:将 [中文], [英语], [数学] 这些列的名称和值重新提取回两列:Subject(列名)和 Score(列值)。
  • 关键区别:UNPIVOT 不需要聚合函数,因为它是在已经是“结果集”的基础上进行展开。
-- 先进行一次 Pivot 得到宽表,再立即 Unpivot 还原
select StudentName,
    Subject,
    Score
 from
(select * from @t) t1
pivot (sum(Score) for Subject in([中文],[英语],[数学])) t2
unpivot (Score for Subject in([中文],[英语],[数学])) t3

第2步:比对原始数据

执行上述嵌套查询后,输出的数据应当与最初插入 @t 表的原始行数一致。这一步不仅验证了转换的准确性,也展示了如何利用这两个关键字进行数据的“变换-还原”循环测试。

总结与注意事项

  • 性能考量:对于小规模数据,两者性能差异可忽略。但在大数据量下,PIVOT 可能涉及更多的内部索引查找和内存分配,建议在实际生产环境中针对具体数据集进行基准测试。
  • 动态列处理:无论是 CASE 还是 PIVOT,如果科目名称是动态变化的(例如每个月份不同),都需要通过动态 SQL(Dynamic SQL)拼接语句来实现,静态 SQL 无法适应完全未知的列头。
  • 空值处理:在 PIVOT 中,如果某个学生在某科缺席导致无数据,该位置默认显示 NULL。如果需要默认值,可以在外层包裹 ISNULL() 或使用之前的 ELSE 0 技巧(但需注意 PIVOT 本身的机制是直接映射列名)。
以上就是关于 SQL Server 行列互转的详细实现思路,更多关于数据库查询优化的资料请关注本站其它相关文章!
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。