本文介绍了SQL Server中多行多列转单行单列的高效处理方案,详细阐述了如何从传统的PIVOT操作过渡到JSON格式的灵活应用,通过代码示例展示了结合两者优势的解决方案,旨在解决数据透视难题,提升查询的灵活性与效率。
在数据库查询和数据报表开发中,我们经常遇到这样的需求:将一张“长格式”的数据表,转换成“宽格式”的表格,也就是实现SQL Server多行多列变一行一列的操作,这种操作通常被称为“数据透视”。
在学生成绩表中,每一行代表一个学生的单科成绩,我们需要将其转换为每一行代表一个学生,且包含所有科目成绩的格式。
本文将介绍两种最主流的方法:传统的 PIVOT 操作和现代的 FOR JSON 方法,并对比它们的优缺点。

场景模拟
我们构建一个简单的数据表 StudentScores,包含学生姓名、科目和分数:
CREATE TABLE StudentScores (
StudentName NVARCHAR(50),
Subject NVARCHAR(50),
Score INT
);
INSERT INTO StudentScores VALUES
('张三', '语文', 85),
('张三', '数学', 92),
('张三', '英语', 78),
('李四', '语文', 76),
('李四', '数学', 88),
('李四', '英语', 95);
目前的查询结果是一个标准的“多行多列”结构,我们的目标是将其变为“一行一列”的宽表结构。
方法一:使用 PIVOT(透视)运算符
PIVOT 是 SQL Server 中专门用于行转列的运算符,它通过聚合函数(如 MAX, SUM)将指定的列值旋转为新的列名。
语法核心:
SELECT ... FROM ... PIVOT (聚合函数(列) FOR 转换列 IN (目标列列表))
代码示例:
SELECT *
FROM (
-- 子查询:先按学生分组
SELECT StudentName, Subject, Score
FROM StudentScores
) AS SourceTable
PIVOT (
-- 聚合函数:取最大分(也可以是 SUM)
MAX(Score)
-- FOR 关键字:将 Subject 列的值变为新列名
FOR Subject IN ([语文], [数学], [英语])
) AS PivotTable;
结果展示: 数据已经成功实现了SQL Server多行多列变一行一列,每一行代表一个学生,列名对应具体的科目。
局限性:
PIVOT 的缺点是必须显式列出所有的目标列(如 [语文], [数学]),如果科目是动态变化的,编写静态的 PIVOT 语句会非常麻烦,这时就需要配合动态 SQL 使用。
方法二:使用 FOR JSON PATH(JSON 透视)
如果你的 SQL Server 版本是 2016 或更高版本,FOR JSON 是一个更现代、更强大的选择,它不需要预先知道列名,能够将多行数据自动合并为一个 JSON 对象,非常适合 Web API 开发或复杂的报表输出。
语法核心:
SELECT ... FROM ... FOR JSON PATH
代码示例:
SELECT
StudentName,
Subject,
Score
FROM StudentScores
FOR JSON PATH, ROOT('StudentList');
结果展示: 这会返回一段 JSON 字符串:
[
{
"StudentName": "张三",
"Score": {
"语文": 85,
"数学": 92,
"英语": 78
}
},
...
]
虽然这返回的是文本,但在逻辑上它完美地实现了**SQL Server多行

