-- 按地区汇总各月销售额,将月份行转为列
SELECT
region,
SUM(CASE WHEN month = '2024-01' THEN amount ELSE 0 END) AS jan_amount,
SUM(CASE WHEN month = '2024-02' THEN amount ELSE 0 END) AS feb_amount,
SUM(CASE WHEN month = '2024-03' THEN amount ELSE 0 END) AS mar_amount
FROM doc_pivot_sales
GROUP BY region
ORDER BY region;
执行结果:
region
jan_amount
feb_amount
mar_amount
华东
2000
2450
2900
华北
1200
1470
1750
华南
1500
1850
2180
说明:
CASE WHEN month = '2024-01' THEN amount ELSE 0 END
CASE WHEN month = '2024-01' THEN amount ELSE 0 END
对每行判断月份,只有匹配的行才贡献金额,其余行贡献 0。
SUM
SUM
将同一地区的所有行聚合,最终每个地区只剩一行,月份信息变为列。
场景二:列转行(UNPIVOT)
将宽表中的多个季度列(
q1_amount
q1_amount
、
q2_amount
q2_amount
、
q3_amount
q3_amount
、
q4_amount
q4_amount
)转换为
quarter
quarter
+
amount
amount
两列的长表格式,便于统一处理或绘制折线图。
首先创建宽表示例数据:
-- 创建宽表(每个地区一行,四个季度各一列)
CREATE TABLE IF NOT EXISTS doc_pivot_wide (
region STRING,
q1_amount DOUBLE,
q2_amount DOUBLE,
q3_amount DOUBLE,
q4_amount DOUBLE
);
INSERT INTO doc_pivot_wide VALUES
('华东', 2000, 2450, 2900, 3100),
('华南', 1500, 1850, 2180, 2400),
('华北', 1200, 1470, 1750, 1900);
使用
UNION ALL
UNION ALL
将四列展开为多行:
-- 列转行:将 q1~q4 四列合并为 quarter + amount 两列
SELECT region, 'Q1' AS quarter, q1_amount AS amount FROM doc_pivot_wide
UNION ALL
SELECT region, 'Q2', q2_amount FROM doc_pivot_wide
UNION ALL
SELECT region, 'Q3', q3_amount FROM doc_pivot_wide
UNION ALL
SELECT region, 'Q4', q4_amount FROM doc_pivot_wide
ORDER BY region, quarter;
执行结果:
region
quarter
amount
华东
Q1
2000
华东
Q2
2450
华东
Q3
2900
华东
Q4
3100
华北
Q1
1200
华北
Q2
1470
华北
Q3
1750
华北
Q4
1900
华南
Q1
1500
华南
Q2
1850
华南
Q3
2180
华南
Q4
2400
说明:每个
SELECT
SELECT
子句对应一列,
UNION ALL
UNION ALL
将结果纵向拼接。列数越多,
UNION ALL
UNION ALL
的子句越多,但逻辑清晰,易于维护。
场景三:交叉表统计
统计每个月份在各地区的销售额,形成月份 × 地区的二维矩阵,适合制作交叉报表。
-- 月份 × 地区交叉表:每行一个月份,每列一个地区
SELECT
month,
SUM(CASE WHEN region = '华东' THEN amount ELSE 0 END) AS east_amount,
SUM(CASE WHEN region = '华南' THEN amount ELSE 0 END) AS south_amount,
SUM(CASE WHEN region = '华北' THEN amount ELSE 0 END) AS north_amount,
SUM(amount) AS total_amount
FROM doc_pivot_sales
GROUP BY month
ORDER BY month;
执行结果:
month
east_amount
south_amount
north_amount
total_amount
2024-01
2000
1500
1200
4700
2024-02
2450
1850
1470
5770
2024-03
2900
2180
1750
6830
也可以按地区为行、产品为列,统计各地区两种产品的销售额及合计:
-- 地区 × 产品交叉表:每行一个地区,每列一种产品
SELECT
region,
SUM(CASE WHEN product = '产品A' THEN amount ELSE 0 END) AS product_a_total,
SUM(CASE WHEN product = '产品B' THEN amount ELSE 0 END) AS product_b_total,
SUM(amount) AS grand_total
FROM doc_pivot_sales
GROUP BY region
ORDER BY region;
执行结果:
region
product_a_total
product_b_total
grand_total
华东
4500
2850
7350
华北
2550
1870
4420
华南
3300
2230
5530
说明:交叉表本质上是行转列的扩展,通过在
CASE WHEN
CASE WHEN
中枚举维度值来构造列。当维度值较多时,可先用
SELECT DISTINCT
SELECT DISTINCT
查出所有维度值,再动态拼接 SQL。
场景四:多值列展开
当一列中存储了逗号分隔的多个值(如标签、产品列表),需要将每个值展开为独立的行,以便进行统计分析。
首先创建包含多值列的示例表:
-- 创建订单标签表(tags 列存储逗号分隔的产品标签)
CREATE TABLE IF NOT EXISTS doc_pivot_tags (
order_id INT,
region STRING,
tags STRING
);
INSERT INTO doc_pivot_tags VALUES
(1, '华东', '产品A,产品B'),
(2, '华南', '产品A'),
(3, '华北', '产品B,产品C'),
(4, '华东', '产品A,产品C'),
(5, '华南', '产品B,产品C');
使用
LATERAL VIEW EXPLODE
LATERAL VIEW EXPLODE
配合
SPLIT
SPLIT
将多值列展开:
-- 将 tags 列按逗号拆分,每个标签展开为独立一行
SELECT
order_id,
region,
tag
FROM doc_pivot_tags
LATERAL VIEW EXPLODE(SPLIT(tags, ',')) t AS tag
ORDER BY order_id, tag;
执行结果:
order_id
region
tag
1
华东
产品A
1
华东
产品B
2
华南
产品A
3
华北
产品B
3
华北
产品C
4
华东
产品A
4
华东
产品C
5
华南
产品B
5
华南
产品C
展开后可直接进行聚合统计,例如统计每种产品出现在多少个订单中:
-- 展开后统计每种产品的订单数
SELECT
tag AS product,
COUNT(*) AS order_count
FROM doc_pivot_tags
LATERAL VIEW EXPLODE(SPLIT(tags, ',')) t AS tag
GROUP BY tag
ORDER BY tag;
-- 第一步:按地区和月份聚合;第二步:将月份列转置为宽表
WITH monthly_summary AS (
SELECT
region,
month,
SUM(amount) AS total_amount
FROM doc_pivot_sales
GROUP BY region, month
)
SELECT
region,
ROUND(SUM(CASE WHEN month = '2024-01' THEN total_amount ELSE 0 END), 2) AS m1,
ROUND(SUM(CASE WHEN month = '2024-02' THEN total_amount ELSE 0 END), 2) AS m2,
ROUND(SUM(CASE WHEN month = '2024-03' THEN total_amount ELSE 0 END), 2) AS m3,
ROUND(SUM(total_amount), 2) AS total
FROM monthly_summary
GROUP BY region
ORDER BY region;
执行结果:
region
m1
m2
m3
total
华东
2000
2450
2900
7350
华北
1200
1470
1750
4420
华南
1500
1850
2180
5530
说明:CTE(
WITH ... AS
WITH ... AS
)将聚合逻辑与转置逻辑分离,使 SQL 更易读。外层查询只需对 CTE 结果做
CASE WHEN
CASE WHEN
转置,无需重复写聚合条件。
清理测试数据
完成数据透视验证后,建议清理测试表:
DROP TABLE IF EXISTS doc_pivot_sales;
DROP TABLE IF EXISTS doc_pivot_wide;
DROP TABLE IF EXISTS doc_pivot_tags;