MS-SQL 如何在表值中添加缺失的月份

Use*_*854 1 sql sql-server

我有一个包含以下条目的表,

ID 日期 频率
1 '2012-04-30' 5
1 '2012-06-30' 4
1 '2012-07-31' 25
2 '2012-04-30' 7
2 '2012-05-31' 4
2 '2012-06-30' 1
2 '2012-07-31' 6

我需要添加缺失的月份,添加的日期应该是该月的最后一个日期,频率值为 0。

预期输出是

ID 日期 频率
1 '2012-04-30' 5
1 '2012-05-31' 0
1 '2012-06-30' 4
1 '2012-07-31' 25
2 '2012-04-30' 7
2 '2012-05-31' 4
2 '2012-06-30' 1
2 '2012-07-31' 6

我需要添加缺失的月份,添加的日期应该是该月份的最后一个日期

Gor*_*off 5

我建议使用递归 CTE:

with cte as (
      select id, date, frequency,
             lead(date) over (partition by id order by date) as next_date
      from t
      union all
      select id, eomonth(date, 1), 0, next_date
      from cte
      where eomonth(date, 1) < dateadd(day, -1, next_date)
     )
select id, date, frequency
from cte
order by id, date;
Run Code Online (Sandbox Code Playgroud)

CTE 的锚点部分计算给定行的结束日期。然后,递归部分不断添加月份来填充缺失的行(如果没有,则不填充)。使用eomonth(date, 1)只是获取下个月最后一天的便捷方法。

是一个 db<>fiddle。

如果表中包含所有日期,您还可以使用cross join来生成行,然后left join引入现有数据:

select i.id, d.date, coalesce(t.frequency, 0) as frequency
from (select distinct id from t) i cross join
     (select distinct date from t) d left join
     t
     on i.id = t.id and d.date = t.date
order by i.id, d.date;
Run Code Online (Sandbox Code Playgroud)

如果数据量很大,可以比较性能。在这种情况下,递归 CTE 可能比其他方法更快。