SQL 如何实现行转列(Pivot)?

10次阅读

sql行转列核心是将离散值作新列名并旋转数据,通用写法为CASE WHEN+GROUP BY聚合,SQL Server/oracle支持PIVOT关键字,mysql需用CASE WHEN模拟,动态列需应用层处理。

SQL 如何实现行转列(Pivot)?

SQL 行转列(Pivot)的核心是把某一列的**离散值**作为新列名,将对应的数据“旋转”过去。不同数据库语法差异较大,但思路一致:先聚合(避免多行冲突),再按条件分组展开。

标准 SQL(通用写法:CASE WHEN + GROUP BY)

这是兼容性最强的方式,适用于 MySQL、postgresql、SQL Server、Oracle 等所有主流数据库。

  • CASE WHEN 对目标列的每个值单独提取,生成新列表达式
  • 配合 MAX()/SUM()/count()聚合函数,确保每组只返回一个值
  • 必须搭配 GROUP BY 原始分组字段(如用户ID、日期等)

示例:将订单表中按商品类别的销售额转为横向列

select    order_date,   MAX(CASE WHEN category = '电子' THEN amount END) AS 电子,   MAX(CASE WHEN category = '服装' THEN amount END) AS 服装,   MAX(CASE WHEN category = '食品' THEN amount END) AS 食品 FROM orders GROUP BY order_date;

SQL Server / Oracle:使用内置 PIVOT 关键字

语法更简洁,但要求明确指定列名,且不支持动态列(列名需写死)。

  • SQL Server 示例:
SELECT order_date, [电子], [服装], [食品] FROM (   SELECT order_date, category, amount FROM orders ) AS src PIVOT (   SUM(amount) FOR category IN ([电子], [服装], [食品]) ) AS pvt;
  • Oracle 11g+ 支持类似语法,关键字相同,括号内列名用双引号(如 “电子”)

MySQL 8.0+:窗口函数辅助 + GROUP BY(无原生 PIVOT)

MySQL 没有 PIVOT 关键字,仍推荐 CASE WHEN 方式。若需动态列(比如类别不固定),必须靠应用层拼接 SQL 或用存储过程模拟。

  • 动态场景常见于报表系统,数据库本身无法自动推导列名
  • 可先查出所有 category 值:SELECT DISTINCT category FROM orders,再由程序生成完整 SQL

注意事项与常见坑

行转列不是“魔法”,本质是分组聚合后的结构重排,容易出错的点包括:

  • 忘记加聚合函数 → 报错或结果不全(尤其是多条同组记录时)
  • GROUP BY 字段漏掉关键维度 → 数据合并错误
  • NULL 值未处理 → 转换后列中出现大量 NULL,影响后续计算或展示
  • 字符串列用于 pivot 时未加引号或转义 → 语法错误(尤其在动态 SQL 中)

text=ZqhQzanResources