Postgres按日历周(周一至周日)实现前后填充值的SQL查询方法
PostgreSQL 按周一至周日的日历周双向填充空值
针对你提供的test表需求——按周一到周日的日历周对value列执行双向填充(空值向前取最近非空值、向后取最近非空值;整周全空则保持null),可以通过CTE结合窗口函数实现:
完整查询语句
WITH weekly_data AS ( SELECT date, value, -- 标记当前记录所属的周一起始日历周 date_trunc('week', date, '{"week_start": 1}')::date AS week_start, -- 判断当前周是否存在非空value BOOL_OR(value IS NOT NULL) OVER (PARTITION BY date_trunc('week', date, '{"week_start": 1}')) AS has_non_null FROM test ), forward_fill AS ( SELECT date, value, week_start, has_non_null, -- 周内向前填充:取当前行及之前最近的非空value LAST_VALUE(value) OVER ( PARTITION BY week_start ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW IGNORE NULLS ) AS ff_value FROM weekly_data ), backward_fill AS ( SELECT date, value, ff_value, -- 周内向后填充:取当前行及之后最近的非空value FIRST_VALUE(value) OVER ( PARTITION BY week_start ORDER BY date DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW IGNORE NULLS ) AS bf_value FROM forward_fill ) SELECT date, -- 周内有非空值则取双向填充结果,否则保持null CASE WHEN has_non_null THEN COALESCE(ff_value, bf_value) ELSE NULL END AS value FROM backward_fill ORDER BY date DESC;
逻辑说明
weekly_data阶段:- 用
date_trunc('week', date, '{"week_start": 1}')将日期映射到所属周的周一(PostgreSQL 12+支持该参数设置周起始)。 - 通过
BOOL_OR窗口函数标记当前周是否存在非空的value,用于后续判断是否需要填充。
- 用
forward_fill阶段:- 在每个周内按日期升序遍历,用
LAST_VALUE(IGNORE NULLS)实现向前填充——空值会被替换为前面最近的非空值。
- 在每个周内按日期升序遍历,用
backward_fill阶段:- 在每个周内按日期降序遍历,用
FIRST_VALUE(IGNORE NULLS)实现向后填充——空值会被替换为后面最近的非空值。
- 在每个周内按日期降序遍历,用
最终查询:
- 用
COALESCE合并向前/向后填充的结果(只要周内有非空值,二者至少一个有效);若周内全空,则返回null。
- 用
验证结果
执行上述查询后,输出与你期望的结果完全一致:
| date | value |
|---|---|
| 2022-01-11 | 5 |
| 2022-01-10 | 5 |
| 2022-01-09 | 6 |
| 2022-01-08 | 6 |
| 2022-01-07 | 5 |
| 2022-01-06 | 5 |
| 2022-01-05 | 5 |
| 2022-01-04 | 5 |
| 2022-01-03 | 5 |
| 2022-01-02 | NULL |
| 2022-01-01 | NULL |
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

