在数据世界中,数据的“形状”往往决定分析的效率。例如:
这就是行转列(Pivot)的核心价值——将冗长的纵向数据“压缩”为横向结构,让分析更高效。本文将通过实战案例,手把手教你掌握 SQL 中行转列的3 种核心方法,并揭示高手的隐藏技巧。
问题场景:
假设有一张销售表 sales
:
year | quarter | revenue |
---|---|---|
2023 | Q1 | 5000 |
2023 | Q2 | 7000 |
2023 | Q3 | 6000 |
2023 | Q4 | 8000 |
目标: 将季度(Q1-Q4)转换为列,输出:
year | Q1 | Q2 | Q3 | Q4 |
---|---|---|---|---|
2023 | 5000 | 7000 | 6000 | 8000 |
核心逻辑:
CASE WHEN
)将行数据映射到对应列。前置 SQL:
CREATE TABLE`sales` (
`year`varchar(255) CHARACTERSET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULLDEFAULTNULL,
`quarter`varchar(255) CHARACTERSET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULLDEFAULTNULL,
`revenue`varchar(255) CHARACTERSET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULLDEFAULTNULL
) ENGINE = InnoDBCHARACTERSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
INSERTINTO`sales`VALUES ('2023', 'Q2', '7000');
INSERTINTO`sales`VALUES ('2023', 'Q3', '6000');
INSERTINTO`sales`VALUES ('2023', 'Q4', '8000');
INSERTINTO`sales`VALUES ('2023', 'Q1', '5000');
适用场景:所有 SQL 数据库(MySQL、PostgreSQL、SQL Server 等)。 代码示例:
SELECT
year,
SUM(CASEWHENquarter = 'Q1'THEN revenue ELSE0END) AS Q1,
SUM(CASEWHENquarter = 'Q2'THEN revenue ELSE0END) AS Q2,
SUM(CASEWHENquarter = 'Q3'THEN revenue ELSE0END) AS Q3,
SUM(CASEWHENquarter = 'Q4'THEN revenue ELSE0END) AS Q4
FROM sales
GROUPBYyear;
关键点:
优势:
MAX()
、AVG()
)。适用场景:SQL Server、Oracle、Snowflake 等支持PIVOT
的数据库。
代码示例:
SELECT *
FROM sales
PIVOT (
SUM(revenue)
FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4')
) AS pivot_table;
关键点:
quarter
)和目标列值(Q1-Q4)。SUM()
会自动对每个季度的revenue
求和。优势:
局限性:
PIVOT
。适用场景:列名未知或动态变化(如 quarter )。 实现思路:
CASE WHEN
条件。示例(MySql):
-- 1. 获取所有列名
SET @cols = NULL;
SELECTGROUP_CONCAT(DISTINCTCONCAT('SUM(CASE WHEN quarter = ''', quarter, ''' THEN revenue END) AS ', quarter))
INTO @cols
FROM sales;
-- 2. 拼接完整SQL语句
SET @sql = CONCAT(
'SELECT year, ', @cols,
' FROM sales
GROUP BY year'
);
-- 3. 执行动态SQL
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATEPREPARE stmt;
优势:
需求:按年份和产品类型,统计各季度销售额。 原始数据:
year | product | quarter | revenue |
---|---|---|---|
2023 | A | Q1 | 3000 |
2023 | A | Q2 | 4000 |
2023 | B | Q1 | 2000 |
2023 | B | Q2 | 3000 |
SQL 代码(CASE WHEN):
SELECT
year,
product,
SUM(CASEWHENquarter = 'Q1'THEN revenue ELSE0END) AS Q1,
SUM(CASEWHENquarter = 'Q2'THEN revenue ELSE0END) AS Q2
FROM sales
GROUPBYyear, product;
输出:
year | product | Q1 | Q2 |
---|---|---|---|
2023 | A | 3000 | 4000 |
2023 | B | 2000 | 3000 |
需求:统计不同地区的用户注册渠道(渠道为文本列)。 原始数据:
region | channel | count |
---|---|---|
北京 | 线上 | 150 |
北京 | 线下 | 100 |
上海 | 线上 | 200 |
SQL 代码(PIVOT):
SELECT region, [线上], [线下]
FROM (
SELECT region, channel, count
FROM user_registration
) AS src
PIVOT (
SUM(count)
FOR channel IN ([线上], [线下])
) AS pvt;
输出:
region | 线上 | 线下 |
---|---|---|
北京 | 150 | 100 |
上海 | 200 | NULL |
quarter
、year
等分组列上建立索引。WHERE
子句过滤无关数据。NULL 值处理:
-- 替换NULL为0
COALESCE(SUM(...), 0) AS column_name
列名冲突:
使用AS
关键字重命名列(如AS [Q1_Sales]
)。
在转列前,先通过窗口函数计算累计值:
SELECT
year,
SUM(CASEWHENquarter = 'Q1'THEN revenue END) AS Q1,
SUM(CASEWHENquarter = 'Q2'THEN revenue END) AS Q2,
SUM(CASEWHENquarter = 'Q3'THEN revenue END) AS Q3,
SUM(CASEWHENquarter = 'Q4'THEN revenue END) AS Q4,
-- 计算累计值
SUM(revenue) OVER (PARTITIONBYyearORDERBYquarter) AS cumulative
FROM sales
GROUPBYyear, quarter;
方法 | 适用场景 | 代码复杂度 | 兼容性 |
---|---|---|---|
CASE WHEN | 全平台通用,动态列适配 | 中 | 所有数据库 |
PIVOT | 简洁高效,列名固定 | 低 | SQL Server 等 |
动态 SQL 生成 | 列名未知或动态变化 | 高 | 需程序支持 |
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有