示例说明
SQL 没有内建的 PIVOT 语法,行转列的标准答案是条件聚合:每个输出列对应一个条件分支,聚合时只有匹配行的值参与求和。FILTER 子句是比 CASE WHEN 更清爽的写法——条件写在聚合外面,ELSE 零值的填充语义由 COALESCE 在外层按需补。列的集合是静态的,动态范围要靠应用层拼接。
技术要点
- FILTER 子句的条件聚合最简洁
- 每列一个条件分支的透视范式
- DISTINCT 月份供动态列清单
代码解读
第一种写法三个月份列加总计列,FILTER 的 NULL 语义让 SUM 自动跳过不匹配行——不需要 ELSE 零;第二种 CASE 写法的行为等价,兼容不支持 FILTER 的引擎。末尾查询输出区间内的月份清单,应用层遍历它生成列定义再拼最终 SQL。
使用建议
列数随时间无限增长时改按年拆表或转 JSON 输出。FILTER 与 CASE 的空值语义差异在 AVG 上更明显。动态拼 SQL 必须白名单化月份值。
代码示例
-- 固定月份的手写透视:CASE 进聚合函数
SELECT
category,
SUM(amount) FILTER (WHERE month = '2026-07') AS jul_revenue,
SUM(amount) FILTER (WHERE month = '2026-08') AS aug_revenue,
SUM(amount) FILTER (WHERE month = '2026-09') AS sep_revenue,
SUM(amount) AS total_revenue
FROM monthly_revenue
GROUP BY category
ORDER BY total_revenue DESC;
-- 经典写法对照:CASE WHEN 的条件聚合
SELECT
category,
SUM(CASE WHEN month = '2026-07' THEN amount ELSE 0 END) AS jul_revenue,
SUM(CASE WHEN month = '2026-08' THEN amount ELSE 0 END) AS aug_revenue
FROM monthly_revenue
GROUP BY category;
-- 生成动态列清单(应用层据此拼 SQL)
SELECT DISTINCT month
FROM monthly_revenue
WHERE month BETWEEN '2026-07' AND '2026-09'
ORDER BY month;