You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL查询如何补全缺失月份并自动填充上月对应记录值

问题描述

我有一个首列为月份的结果集,其中部分月份存在缺失,我需要为这些缺失的月份补入对应上月的记录,直到最近一个月为止。

当前数据如下:
当前数据示意图

期望输出效果:
期望输出示意图

我自行编写了一段SQL,但运行后不是仅填充缺失月份,而是基于所有行重复生成了数据,代码如下:

select 
to_char(generate_series(date_trunc('MONTH',to_date(period,'YYYYMMDD')+interval '1' month),
              date_trunc('MONTH',now()+interval '1' day), 
              interval '1' month) - interval '1 day','YYYYMMDD') as period, 
name,age,salary,rating
from( values ('20201205','Alex',35,100,'A+'),
            ('20210110','Alex',35,110,'A'),
            ('20210512','Alex',35,999,'A+'),
            ('20210625','Jhon',20,175,'B-'),
            ('20210922','Jhon',20,200,'B+')) v (period,name,age,salary,rating) order by 2,3,4,5,1;

该查询的实际输出如下:
实际输出示意图

请问如何修改SQL才能得到期望的输出?


解决方案

你现有SQL的问题是直接为每条原始记录生成后续全量月份,没有按用户做分组限制,也没有处理缺失行的字段填充逻辑,修改后的SQL如下:

WITH raw_data AS (
    -- 原始数据统一转成月末日期格式,方便后续关联
    SELECT 
        to_char(date_trunc('MONTH', to_date(period, 'YYYYMMDD')) + INTERVAL '1 month - 1 day', 'YYYYMMDD') AS month_end,
        name,
        age,
        salary,
        rating
    FROM (
        VALUES 
            ('20201205','Alex',35,100,'A+'),
            ('20210110','Alex',35,110,'A'),
            ('20210512','Alex',35,999,'A+'),
            ('20210625','Jhon',20,175,'B-'),
            ('20210922','Jhon',20,200,'B+')
    ) v (period,name,age,salary,rating)
),
user_time_range AS (
    -- 按用户统计最早记录月份、需要填充到的最新月份(当前月)
    SELECT 
        name,
        min(date_trunc('MONTH', to_date(month_end, 'YYYYMMDD'))) AS min_month,
        date_trunc('MONTH', now() + INTERVAL '1 day') AS max_month
    FROM raw_data
    GROUP BY name
),
all_user_months AS (
    -- 为每个用户单独生成连续的月末日期序列
    SELECT 
        name,
        to_char(generate_series(min_month, max_month, INTERVAL '1 month') + INTERVAL '1 month - 1 day', 'YYYYMMDD') AS period
    FROM user_time_range
)
-- 左关联原始数据,用窗口函数填充空值
SELECT 
    a.period,
    a.name,
    last_value(r.age) IGNORE NULLS OVER (PARTITION BY a.name ORDER BY a.period) AS age,
    last_value(r.salary) IGNORE NULLS OVER (PARTITION BY a.name ORDER BY a.period) AS salary,
    last_value(r.rating) IGNORE NULLS OVER (PARTITION BY a.name ORDER BY a.period) AS rating
FROM all_user_months a
LEFT JOIN raw_data r ON a.name = r.name AND a.period = r.month_end
ORDER BY a.name, a.period;

逻辑说明

  1. 统一原始数据的日期格式为对应月份的月末,避免同月份不同日期的关联匹配问题
  2. 按用户维度单独计算各自的时间范围,避免跨用户生成多余日期
  3. 左关联后通过last_value() IGNORE NULLS窗口函数,取当前用户当前行之前最近的非空值填充缺失字段,即可得到预期结果。

内容的提问来源于stack exchange,提问作者Anupam Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 10:36:05