Clickhouse实现累计求和cumulative sum

源表数据如下:

time province order_cnt
20200601 shandong 100
20200601 jiangsu 200
20200601 zhejiang 300
20200602 shandong 200
20200602 jiangsu 300
20200602 zhejiang 400
20200603 shandong 400
20200603 jiangsu 500
20200603 zhejiang 600

需求是按照省份和时间分类,每天累计求和,需求的结果如下:
(每天的数据都要按照省份将之前的订单数目进行累加)

time province order_cnt_sum
202
<think> 我们正在解决的是SQL中实现累计求和的方法。累计求和通常指的是对于某个列,从第一行到当前行的累加。根据引用[2]和引用[3],我们可以通过自连接或者窗口函数来实现。 引用[2]中展示了使用自连接的方法:首先按月份分组求和,然后通过自连接和条件(B.month <= A.month)来累计求和。这种方法在数据量大时可能效率较低。 引用[3]和引用[1]则使用了窗口函数(over子句)来实现,这是更高效的方法。引用[3]中的帕累托求和(即累计求和)使用了`sum(sale_num) over(partition by sku_id order by order_id)`,这里没有指定窗口范围,默认是当前行及其之前的所有行。 因此,我们可以总结两种方法: 方法1:使用自连接(适用于不支持窗口函数的数据库,但效率较低) 方法2:使用窗口函数(推荐,效率高) 下面我们分别用两种方法实现累计求和。 ### 示例数据 假设我们有一个销售表`sales`,包含以下字段: - `date`:日期 - `amount`:每日销售额 我们想要计算累计销售额,即每天从开始到当天的销售额总和。 ### 方法1:自连接 ```sql SELECT a.date, a.amount, SUM(b.amount) AS cumulative_sum FROM sales a JOIN sales b ON b.date <= a.date GROUP BY a.date, a.amount ORDER BY a.date; ``` ### 方法2:窗口函数(推荐) ```sql SELECT date, amount, SUM(amount) OVER (ORDER BY date) AS cumulative_sum FROM sales ORDER BY date; ``` 在窗口函数中,我们使用`ORDER BY date`来指定累计的顺序,并且没有使用`PARTITION BY`,意味着整个表作为一个分区进行累计。如果需要按某个字段分组累计(比如每个产品),则可以在`PARTITION BY`中指定分组字段。 ### 分组累计求和示例 例如,按产品分组计算累计销售额: ```sql SELECT product_id, date, amount, SUM(amount) OVER (PARTITION BY product_id ORDER BY date) AS cumulative_sum FROM sales ORDER BY product_id, date; ``` ### 总结 - 累计求和是常见的分析需,使用窗口函数更高效简洁。 - 在支持窗口函数的数据库(如MySQL 8.0+、PostgreSQL、SQL Server、Oracle、Impala、Hive等)中,推荐使用窗口函数。 - 如果数据库不支持窗口函数,可以使用自连接,但要注意性能问题。 §§相关问题§§ 1. SQL中窗口函数还有哪些常见用法? 2. 如何优化使用自连接的累计求和查询? 3. 在MySQL 5.7及以下版本中如何实现累计求和? 4. 累计求和和滑动窗口求和有什么区别? </think> ### SQL实现累计求和的方法 在SQL中实现累计求和主要有两种高效方法,下面我将详细说明实现步骤和示例代码: #### 方法1:窗口函数法(推荐)✅ 这是最高效简洁的实现方式,使用`SUM() OVER()`窗口函数: ```sql SELECT date, amount, SUM(amount) OVER (ORDER BY date) AS cumulative_sum FROM sales_table ORDER BY date; ``` **参数说明**: - `SUM(amount)`:计算累计 - `OVER (ORDER BY date)`:按日期排序累计 - 默认范围:从分区第一行到当前行[^1][^3] **分组累计示例**(如按产品类别累计): ```sql SELECT product_id, date, amount, SUM(amount) OVER ( PARTITION BY product_id ORDER BY date ) AS cumulative_per_product FROM sales; ``` #### 方法2:自连接法(兼容旧版本SQL) 适用于不支持窗口函数的数据库: ```sql SELECT a.date, a.amount, SUM(b.amount) AS cumulative_sum FROM sales a JOIN sales b ON b.date <= a.date GROUP BY a.date, a.amount ORDER BY a.date; ``` **实现原理**: 1. 表自连接创建笛卡尔积 2. 通过`b.date <= a.date`筛选早于当前行的记录 3. 对早于当前行的分组求和[^2] #### 两种方法对比 | 特性 | 窗口函数法 | 自连接法 | |--------------|--------------------|--------------------| | 性能 | ⭐⭐⭐⭐ 高效 | ⭐⭐ 数据量大时慢 | | 代码复杂度 | ⭐ 简洁 | ⭐⭐⭐ 复杂 | | 兼容性 | MySQL 8.0+/PG等 | 所有SQL版本 | | 可读性 | 直观 | 较难理解 | **实际应用建议**: 1. 现代数据库优先选用窗口函数(性能提升5-10倍) 2. 超大数据集可增加分区字段优化:`PARTITION BY category` 3. 历史数据累计需注意NULL处理:`COALESCE(amount,0)` 4. 结合索引:在`ORDER BY`和`PARTITION BY`字段建索引[^1][^3] > 窗口函数是SQL标准(SQL:2003)的一部分,已在主流数据库实现累计求和这类分析操作应首选此方案[^1][^3]。
评论 9
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值