SQL查询需求:计算时间段内各数值区间的差值总和
用SQL实现数值区间差值总和计算
这个需求完全可以用单条SQL查询实现,而且基于集合的操作性能会比逐行遍历高效得多。我先拆解你的需求逻辑,再给出对应的查询语句:
需求逻辑拆解
从你的示例结果反推,你需要:
- 把数据按
0分割成多个区间:- 第一个区间:从表的第一条记录到第一个
0的前一条记录,计算区间最大值 - 区间起始值; - 后续每个区间:从一个
0之后到下一个0之前的记录,计算区间最大值 - 对应分割用的0的值;
- 第一个区间:从表的第一条记录到第一个
- 最后把所有区间的差值累加得到总和。
实现SQL(兼容MySQL8+、PostgreSQL、SQL Server等)
假设你的表名为value_log,我们用CTE和窗口函数来实现:
WITH grouped_data AS ( SELECT Value, Time, -- 按0分割组:每遇到一个0,组ID递增 SUM(CASE WHEN Value = 0 THEN 1 ELSE 0 END) OVER (ORDER BY Time) AS group_id FROM value_log ), group_start_values AS ( SELECT group_id, -- 第一个组的起始值是组内第一条记录的值,其他组起始值为0(分割用的0) CASE WHEN group_id = 0 THEN FIRST_VALUE(Value) OVER (PARTITION BY group_id ORDER BY Time) ELSE 0 END AS start_value FROM grouped_data ), group_max_values AS ( SELECT group_id, -- 计算每个组内非0记录的最大值 MAX(CASE WHEN Value != 0 THEN Value END) AS max_value FROM grouped_data GROUP BY group_id ) -- 累加所有有效区间的差值(过滤掉只有0的无效组) SELECT SUM(gm.max_value - gs.start_value) AS total_diff FROM group_start_values gs JOIN group_max_values gm ON gs.group_id = gm.group_id WHERE gm.max_value IS NOT NULL;
逻辑验证(匹配你的示例数据)
针对你给出的示例数据:
group_id=0:包含5、6、7,start_value=5,max_value=7,差值为7-5=2;group_id=1:包含0、1、2、3、4、5、6,start_value=0,max_value=6,差值为6-0=6;group_id=2:只有0,max_value为NULL,被过滤;
最终总和为2+6=8,完全匹配你的预期结果。
边界情况处理
这个查询还能自动处理以下场景:
- 表的第一条记录就是
0:第一个组会被过滤,后续区间正常计算; - 表的最后一条记录不是
0:最后一个区间的差值会被正常累加; - 连续出现多个
0:中间只包含0的组会被过滤,不影响结果。
内容的提问来源于stack exchange,提问作者user2493388
相关产品推荐
相关产品推荐

