【问题标题】:SQL Server Fill Month Gaps in GroupsSQL Server 分组填充月差
【发布时间】:2020-08-23 09:08:52
【问题描述】:

我有一个如下表:

declare @test table(Aid int, Bid int, CheckMonth date, Avalue decimal(18,2))

insert into @test (Aid, Bid, CheckMonth, Avalue)
values (1, 4, '2014-07-05', 123.00)
      ,(1, 4, '2014-08-01', 467.00)
      ,(1, 4, '2014-11-03', 876.00)
      ,(1, 4, '2014-12-01', 876.00)
      ,(2, 6, '2016-01-02', 23.00)
      ,(2, 6, '2016-03-14', 56.00)
      ,(2, 6, '2016-04-17', 98.00)
      ,(2, 6, '2016-07-01', 90.00)

我希望用 0.00 值(在 Avalue 列中)填补月份(在上面的 CheckMonth 列中)的空白。 数据按 Aid 和 Bid 列分组。

结果应如下所示:

Aid   Bid    CheckMonth     Avalue
1     4      '2014-07-05'   123.00
1     4      '2014-08-01'   467.00
1     4      '2014-09-01'   0.00    -->inserted
1     4      '2014-10-01'   0.00    -->inserted
1     4      '2014-11-03'   876.00
1     4      '2014-12-01'   876.00
2     6      '2016-01-02'   23.00
2     6      '2016-02-01'   0.00    -->inserted
2     6      '2016-03-14'   56.00
2     6      '2016-04-17'   98.00
2     6      '2016-05-01'   0.00    -->inserted
2     6      '2016-06-01'   0.00    -->inserted
2     6      '2016-07-01'   90.00

感谢任何帮助。 谢谢。

【问题讨论】:

  • 你试过什么?你在哪里卡住了。
  • @DaleK,我尝试为组创建行号和计数,但它仅适用于一个间隙。间隔超过几个月就不行了
  • 请给我们看!
  • @DaleK,我最初有这个解决方案 使用 FinalData 作为 (select Aid,Bid,CheckMonth,Avalue ,row_number() over(partition by Aid, Bid order by Aid, Bid, CheckMonth) as rowNum , count(*) over(partition by Aid, Bid) as cnt from test) select Aid,Bid,CheckMonth,Avalue from test union select t1.Aid,t1.Bid,dateadd(month, 1, t1.CheckMonth) CheckMonth,0.00从 FinalData t1 左加入 FinalData t2 on t1.rowNum + 1 = t2.rowNum 和 datediff(month, t1.CheckMonth, t2.CheckMonth) in(0,1) 和 t1.Aid = t2.Aid 和 t1.Bid = t2 .Bid 其中 t2.rowNum 为空且 t1.rowNum t1.cnt
  • @DaleK,抱歉格式化。我无法在评论中格式化上述代码

标签: sql-server tsql date sql-server-2014 recursive-query


【解决方案1】:

一个选项使用递归查询为每个(aid, bid) 元组生成月份开始;然后您可以left join 生成的结果集与原始表:

with cte as (
    select 
        aid, 
        bid, 
        datefromparts(year(min(checkMonth)), month(min(checkMonth)), 1) dt, 
        datefromparts(year(max(checkMonth)), month(max(checkMonth)), 1) maxDt 
        from @test
        group by aid, bid
    union all
    select 
        aid, 
        bid, 
        dateadd(month, 1, dt),
        maxDt
    from cte
    where dt < maxDt
)
select c.aid, c.bid, coalesce(t.checkMonth, c.dt) checkMonth, coalesce(t.avalue, 0) avalue 
from cte c
left join @test t 
    on  t.aid = c.aid
    and t.bid = c.bid
    and t.checkMonth >= c.dt
    and t.checkMonth <  dateadd(month, 1, c.dt)
order by c.aid, c.bid, c.dt

Demo on DB Fiddle

援助|出价 |检查月 |一个值 --: | --: | :--------- | :----- 1 | 4 | 2014-07-05 | 123.00 1 | 4 | 2014-08-01 | 467.00 1 | 4 | 2014-09-01 | 0.00 1 | 4 | 2014-10-01 | 0.00 1 | 4 | 2014-11-03 | 876.00 1 | 4 | 2014-12-01 | 876.00 2 | 6 | 2016-01-02 | 23.00 2 | 6 | 2016-02-01 | 0.00 2 | 6 | 2016-03-14 | 56.00 2 | 6 | 2016-04-17 | 98.00 2 | 6 | 2016-05-01 | 0.00 2 | 6 | 2016-06-01 | 0.00 2 | 6 | 2016-07-01 | 90.00

【讨论】:

  • 感谢您,但在实时数据中运行时出现以下错误:Msg 530, Level 16, State 1, Line 1 语句终止。在语句完成之前,最大递归 100 已用完。
  • @ausmod:您的数据分布在 100 多个月内。您可以在查询的最后添加option(maxrecursion 0) 以避免该错误。
  • 再次感谢。我试图将选项语句添加到我的视图的最后一行,就在上面的 order by 语句之前。但我在关键字“选项”附近得到不正确的语法。错误。你知道它必须添加到上面的哪里吗?
  • @ausmod:啊,如果您使用该查询来创建视图,那就不同了。在这种情况下,您需要将选项放在针对视图的每个查询中,而不是在视图本身的定义中。假设您查看的是myview,那么您:select * from myview option(maxrecursion 0)
  • 我认为我们必须在运行包含上述 SQL 语句的视图时添加此选项。正确的?有没有办法将它包含在视图中?谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-10
  • 2017-01-17
  • 1970-01-01
相关资源
最近更新 更多