PostgreSQL:如何将GROUP BY聚合结果转为列展示(行转列)
这是很常见的**行转列(Pivot)**需求,不同数据库的实现方式略有不同,我给你整理了几种主流数据库的解决方案:
先明确你的数据场景
原始数据表 test_table
| ID | Day | Count |
|---|---|---|
| 1 | '1' | 1 |
| 1 | '2' | 2 |
| 1 | '2' | 7 |
| 2 | '2' | 4 |
| 2 | '2' | 3 |
你已完成的聚合结果
通过GROUP BY ID, Day你已经得到了分组后的Count总和:
SELECT ID, Day, SUM(Count) AS total_count FROM test_table GROUP BY ID, Day
结果:
| ID | Day | total_count |
|---|---|---|
| 1 | '1' | 1 |
| 1 | '2' | 9 |
| 2 | '2' | 7 |
实现期望行转列的方案
1. MySQL(无原生PIVOT,用条件聚合)
MySQL没有内置的PIVOT函数,最通用的方式是用条件聚合,通过CASE WHEN结合聚合函数实现:
SELECT ID, SUM(CASE WHEN Day = '1' THEN Count ELSE 0 END) AS Day1, SUM(CASE WHEN Day = '2' THEN Count ELSE 0 END) AS Day2 FROM test_table GROUP BY ID;
逻辑很直观:对每个ID,分别统计Day='1'和Day='2'的Count总和,没有对应Day的记录就返回0。
2. SQL Server(用原生PIVOT语法)
SQL Server支持原生的PIVOT语法,写法更简洁:
SELECT ID, ISNULL([1], 0) AS Day1, ISNULL([2], 0) AS Day2 FROM ( -- 先获取分组后的聚合结果 SELECT ID, Day, SUM(Count) AS total_count FROM test_table GROUP BY ID, Day ) AS grouped_data PIVOT ( SUM(total_count) FOR Day IN ([1], [2]) -- 指定要转成列的Day值 ) AS pivot_table;
用ISNULL把PIVOT返回的NULL替换成0,保证没有对应Day的ID显示0而非空值。
3. PostgreSQL(用crosstab函数)
PostgreSQL可以借助tablefunc扩展里的crosstab函数实现,需要先启用扩展:
-- 仅需执行一次,启用tablefunc扩展 CREATE EXTENSION IF NOT EXISTS tablefunc; -- 执行行转列查询 SELECT ID, COALESCE(Day1, 0) AS Day1, COALESCE(Day2, 0) AS Day2 FROM crosstab( 'SELECT ID, Day, SUM(Count) FROM test_table GROUP BY ID, Day ORDER BY 1,2', 'SELECT DISTINCT Day FROM test_table ORDER BY 1' ) AS ct(ID INT, Day1 INT, Day2 INT);
COALESCE的作用和ISNULL类似,把空值替换成0。
补充说明
如果你的Day取值是动态的(比如未来会新增Day3、Day4),静态写列名的方式就不适用了,这时候需要用动态SQL来自动生成对应的列,不同数据库的动态SQL写法有所差异,比如MySQL用预处理语句,SQL Server用EXEC或sp_executesql。
内容的提问来源于stack exchange,提问作者user1871528
相关产品推荐
相关产品推荐

