面试题:SQL 中如何将 多行合并为一行(合并行数据为列)?

发布于:2025-06-06 ⋅ 阅读:(17) ⋅ 点赞:(0)

✅ 面试题:SQL 中如何将 多行合并为一行(合并行数据为列)?

这是面试和实战中非常常见的场景,属于“行列转换”问题之一,常用于报表聚合、分类汇总、透视表生成等。


go专栏:https://duoke360.com/tutorial/path/golang

一、问题描述

假设有如下数据:

name subject score
张三 语文 80
张三 数学 90
李四 语文 70
李四 数学 85

希望转换成如下结果:

name 语文 数学
张三 80 90
李四 70 85

二、实现方法

✅ 方法1:使用 CASE WHEN + 聚合函数(最通用,兼容所有数据库)
SELECT 
  name,
  MAX(CASE WHEN subject = '语文' THEN score END) AS 语文,
  MAX(CASE WHEN subject = '数学' THEN score END) AS 数学
FROM scores
GROUP BY name;
  • 优点:写法清晰,所有数据库都支持(MySQL、PostgreSQL、SQL Server、Oracle)
  • 缺点:需要提前知道列名(如“语文”“数学”)

✅ 方法2:MySQL 专用的 GROUP_CONCAT() 实现行合并为一列(文本拼接)

例如合并所有科目为一个字符串:

SELECT name, GROUP_CONCAT(CONCAT(subject, ':', score) ORDER BY subject SEPARATOR ', ')
FROM scores
GROUP BY name;

结果示例:

name result
张三 语文:80, 数学:90
李四 语文:70, 数学:85

✅ 方法3:使用 PIVOT(仅适用于 SQL Server / Oracle 11g+)
SELECT * FROM (
  SELECT name, subject, score FROM scores
) AS source
PIVOT (
  MAX(score) FOR subject IN ([语文], [数学])
) AS pvt;

✅ 方法4:PostgreSQL 中使用 FILTER(语法简洁)
SELECT
  name,
  MAX(score) FILTER (WHERE subject = '语文') AS 语文,
  MAX(score) FILTER (WHERE subject = '数学') AS 数学
FROM scores
GROUP BY name;

三、动态列转换(列不固定)

如果列名(如科目)不固定,必须:

  • 在应用层动态拼接 SQL
  • 或使用存储过程、动态 SQL 来生成 CASE 表达式

四、总结比较

方法 是否支持动态列 数据库兼容性 特点
CASE WHEN ❌ 手动写列名 ✅ 所有数据库 最通用,稳定
GROUP_CONCAT ✅ MySQL 专属 多值拼接字符串
PIVOT ✅ SQL Server/Oracle 语法直观,写法简洁
FILTER ✅ PostgreSQL 函数式风格,代码简洁


网站公告

今日签到

点亮在社区的每一天
去签到