如何按日期分组,对各activity的amount求和并实现行列转换?
解决行转列的日期分组汇总问题
你的需求本质是行转列(Pivot):把按行存储的不同activity数据,转换成按列展示的日期维度汇总结果。先说说你原始查询的问题:GROUP BY DISTINCT date是错误用法(GROUP BY本身就会按唯一值分组,不需要额外加DISTINCT),而且没有针对不同activity做拆分聚合,所以得不到预期的分列结果。
下面给你两种通用的解决方案,兼容大多数数据库:
方案一:条件聚合(推荐,兼容性最强)
这种写法适用于MySQL、PostgreSQL、SQLite等几乎所有SQL数据库,逻辑清晰且容易扩展:
SELECT date, -- 汇总当天Shopping的金额,无数据则显示NULL(如果要显示0就把ELSE NULL改成ELSE 0) SUM(CASE WHEN activity = 'Shopping' THEN amount ELSE NULL END) AS Shopping, SUM(CASE WHEN activity = 'Gift' THEN amount ELSE NULL END) AS Gift, -- 注意列名有空格,需要用反引号(MySQL)或方括号(SQL Server)包裹 SUM(CASE WHEN activity = 'Give Away' THEN amount ELSE NULL END) AS `Give Away` FROM your_table GROUP BY date ORDER BY date;
逻辑说明:
- 用
CASE语句对每行的activity做判断,匹配目标类型时取出对应的amount,否则返回NULL - 外层用
SUM函数按date分组汇总,自动把同一日期下同类型的金额累加 ORDER BY date保证结果按日期顺序排列
方案二:用PIVOT函数(仅支持部分数据库)
如果你的数据库支持PIVOT语法(比如SQL Server、Oracle),可以用更简洁的写法:
SELECT date, Shopping, Gift, [Give Away] FROM ( -- 先筛选出需要的基础数据 SELECT date, activity, amount FROM your_table ) AS source_data PIVOT ( -- 指定聚合函数:对amount求和 SUM(amount) -- 指定要转成列的字段:activity的不同值作为列名 FOR activity IN (Shopping, Gift, [Give Away]) ) AS pivot_result ORDER BY date;
逻辑说明:
- 子查询
source_data先取出我们需要的三列数据 PIVOT函数自动把activity的不同取值转成列,并用SUM(amount)完成每个日期下的金额汇总
这两种方案都能得到你想要的结果格式,优先推荐条件聚合,因为它的兼容性更好,而且在需要新增activity类型时,只需要新增一条SUM(CASE...)语句即可。
内容的提问来源于stack exchange,提问作者XIMRX
相关产品推荐
相关产品推荐

