如何在按用户按天及user_id、created_by分组的查询中添加累计求和列?
解决按用户按天统计的累计求和问题
嘿,我明白你要做的事了——在按用户、按天分组的统计结果里,给每个用户加一列从最早日期到当前日期的累计成本总和对吧?其实你已经找对方向了,窗口函数就是解决这个问题的最佳方案,而且完全可以保留user_id和created_by的分组逻辑,我给你一步步讲清楚:
核心思路
我们需要先得到按user_id、created_by和日期分组的每日成本统计,然后在这个结果之上,用窗口函数SUM() OVER()来计算每个用户的累计值。关键是要通过PARTITION BY限定累计的范围(只在同一个用户+created_by组内计算),用ORDER BY指定累计的顺序(按日期从早到晚)。
示例SQL
假设你的原分组查询是类似这样的(我模拟了常见的场景):
SELECT user_id, created_by, DATE(created_at) AS usage_date, SUM(daily_cost_amount_cents) AS daily_cost_amount_cents FROM your_table GROUP BY user_id, created_by, DATE(created_at) ORDER BY user_id, usage_date;
那么只需要在外层或者直接在查询里添加窗口函数,就能得到累计列:
SELECT user_id, created_by, usage_date, daily_cost_amount_cents, -- 这里就是累计求和的窗口函数 SUM(daily_cost_amount_cents) OVER ( PARTITION BY user_id, created_by -- 按用户和created_by分组累计 ORDER BY usage_date -- 按日期顺序累计 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW -- 从第一行累到当前行 ) AS running_total_cents FROM ( -- 这里放你原来的分组查询 SELECT user_id, created_by, DATE(created_at) AS usage_date, SUM(daily_cost_amount_cents) AS daily_cost_amount_cents FROM your_table GROUP BY user_id, created_by, DATE(created_at) ) AS daily_summary ORDER BY user_id, usage_date;
关键部分解释
PARTITION BY user_id, created_by:这一步确保累计计算是严格在同一个user_id和created_by的组合内进行的,不会把不同用户的成本混在一起累计。ORDER BY usage_date:指定按日期从小到大排序,这样累计值会从用户最早的使用日期开始,逐步加到当前日期的数值。ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW:这部分是窗口的范围定义,意思是“从当前分组的第一行一直到当前行”,很多数据库会默认这个范围,但显式写出来会让逻辑更清晰,避免歧义。
效果示例
如果你的原查询返回结果是:
| user_id | created_by | usage_date | daily_cost_amount_cents |
|---|---|---|---|
| 101 | Chris | 2024-05-01 | 500 |
| 101 | Chris | 2024-05-02 | 300 |
| 102 | Emma | 2024-05-01 | 700 |
那么添加累计列后的预期结果就是:
| user_id | created_by | usage_date | daily_cost_amount_cents | running_total_cents |
|---|---|---|---|---|
| 101 | Chris | 2024-05-01 | 500 | 500 |
| 101 | Chris | 2024-05-02 | 300 | 800 |
| 102 | Emma | 2024-05-01 | 700 | 700 |
这个写法在支持窗口函数的数据库(比如PostgreSQL、MySQL 8.0+、SQL Server、BigQuery等)里都能正常运行,完全保留了你需要的分组维度,同时实现了累计求和的需求~
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

