如何修改PostgreSQL查询以返回目标值以上最小累积和对应行
修改PostgreSQL查询以返回累积和首次超过目标值的所有行
需求说明
需要调整现有查询逻辑,让它返回累积和首次超过target_sum的所有行,具体示例:
- 当
target_sum为5时,仅返回id=1的行 - 当
target_sum为8时,返回id=1和id=2的行 - 当
target_sum为13时,返回id=1、2、3的行
数据表结构
| id | marks |
|---|---|
| 1 | 5 |
| 2 | 7 |
| 3 | 6 |
| 4 | 9 |
现有问题
原查询只筛选累积和≤target_sum的行,无法包含首次超过目标值的那一行,不符合需求。
修改后的查询方案
这里提供两种简洁的实现方式:
方案一:标记首超行并筛选
WITH cumulative_data AS ( SELECT *, SUM(marks) OVER (ORDER BY id) AS cum_sum, -- 标记当前行是否超过目标值 CASE WHEN SUM(marks) OVER (ORDER BY id) > target_sum THEN 1 ELSE 0 END AS is_over, -- 获取第一个超过目标值的累积和 FIRST_VALUE(CASE WHEN SUM(marks) OVER (ORDER BY id) > target_sum THEN SUM(marks) OVER (ORDER BY id) END) OVER (ORDER BY id) AS first_over_sum FROM students ) SELECT id, marks, cum_sum FROM cumulative_data WHERE cum_sum <= target_sum OR (is_over = 1 AND cum_sum = first_over_sum) ORDER BY id;
方案二:通过前后行累积和对比
WITH cumulative_data AS ( SELECT *, SUM(marks) OVER (ORDER BY id) AS cum_sum, -- 获取前一行的累积和(首行则为0) COALESCE(SUM(marks) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0) AS prev_cum_sum FROM students ) SELECT id, marks, cum_sum FROM cumulative_data WHERE cum_sum <= target_sum OR (prev_cum_sum <= target_sum AND cum_sum > target_sum) ORDER BY id;
逻辑说明
两种方案核心都是:保留所有累积和未超过目标值的行,同时加上首次超过目标值的那一行。
- 方案一通过窗口函数定位第一个超过目标值的累积和,再筛选出对应行;
- 方案二通过对比当前行与前一行的累积和,判断当前行是否是首次超标的行,进而纳入结果。
内容的提问来源于stack exchange,提问作者sahil
相关产品推荐
相关产品推荐

