← 返回题目列表

SQL 行列转换怎么做?PIVOT、条件聚合和 UNPIVOT 如何选择?

中等 第 24 / 28 题 更新于 2026/07/29
SQLPIVOTUNPIVOT行列转换

简化版

SQL 行列转换分为行转列和列转行。行转列常用条件聚合,例如按月份把销售额转成 jan_amountfeb_amount;部分数据库支持 PIVOT 语法。列转行可以用 UNION ALL 或数据库提供的 UNPIVOT。选择时要看数据库兼容性、列是否固定、是否需要动态 SQL。

详细版

行列转换本质是改变结果集的展示结构。行转列适合报表展示,让多行分类值变成多列指标;列转行适合数据清洗,把宽表变成长表,方便统一聚合和分析。

如果目标列固定,条件聚合最通用。如果目标列来自动态数据,比如动态月份、动态类目,纯静态 SQL 很难生成未知列,通常需要应用层拼 SQL、存储过程或交给 BI 工具。

面试中要强调:SQL 查询结果的列结构通常需要在执行前确定,动态列不是普通 GROUP BY 能直接解决的。

完整版教学

一、行转列的典型场景

原始订单表按月份存多行。

报表希望一个用户一行,每个月销售额一列。

这就是行转列。

行转列关注的是把分类值变成列名。

常见分类包括月份、状态、渠道、等级。

二、条件聚合实现行转列

SELECT
  user_id,
  SUM(CASE WHEN month = '2026-01' THEN amount ELSE 0 END) AS amount_202601,
  SUM(CASE WHEN month = '2026-02' THEN amount ELSE 0 END) AS amount_202602,
  SUM(CASE WHEN month = '2026-03' THEN amount ELSE 0 END) AS amount_202603
FROM sales
GROUP BY user_id;

这种写法兼容性好,适合列集合已知的报表。

三、PIVOT 的特点

方案优点缺点
条件聚合通用、可控、兼容性好列多时代码较长
PIVOT语义直观数据库差异明显
动态 SQL能处理动态列复杂且要防注入
应用层转换灵活数据量大时成本高

四、列转行的典型场景

宽表里有 score_mathscore_englishscore_physics

分析系统希望变成 subjectscore 两列。

这就是列转行。

列转行之后更适合统一筛选、聚合和可视化。

五、UNION ALL 实现列转行

SELECT student_id, 'math' AS subject, score_math AS score FROM scores
UNION ALL
SELECT student_id, 'english' AS subject, score_english AS score FROM scores
UNION ALL
SELECT student_id, 'physics' AS subject, score_physics AS score FROM scores;

如果数据库支持 UNPIVOT,也可以使用专用语法,但跨库兼容性要评估。

六、动态列为什么麻烦

SQL 结果集的列名通常在解析和规划阶段就要确定。

如果月份来自数据表,数据库不会自动把未知数量的月份变成未知数量的列。

动态列需要动态生成 SQL,或者在应用层、BI 层处理。

行列转换的难点不是聚合本身,而是“列集合是否固定”。

七、误区和追问

  • 误区:GROUP BY 可以自动把行变成列。 GROUP BY 只产生分组行,不会自动生成动态列。
  • 误区:PIVOT 是标准通用语法。 不同数据库支持程度和写法差异较大。
  • 误区:动态 SQL 只是字符串拼接。 动态 SQL 要处理权限、注入、执行计划和维护成本。
  • 追问:列很多时条件聚合怎么维护? 可以模板生成 SQL,或交给报表层处理。
  • 追问:行列转换会影响性能吗? 会,尤其是大表聚合和动态转换,要关注过滤条件和预聚合。
  • 追问:为什么列转行常用 UNION ALL? 因为它保留所有行,不做去重,比 UNION 更符合数据展开语义。

八、面试回答重点

先判断行转列还是列转行。

再说明列集合固定用条件聚合或 PIVOT,动态列用动态 SQL 或应用层。

最后补充兼容性和性能风险。