【问题标题】:How can I populate a table in one month increments based on a date如何根据日期以一个月的增量填充表格
【发布时间】:2019-04-15 17:23:30
【问题描述】:

我需要根据另一个表的输入日期加载一个表,该日期介于一个月的第一天和该月的最后一天之间。我需要将负载减少到从当月开始 1 个月的 1 个月的记录价值,然后从当月开始减少 2 个月,依此类推。

我尝试过 CTE,使用光标并手动更改 datediff 参数。最后一种方法有效,但我想动态加载表格

Declare @StartDt as datetime = (SELECT FORMAT(DATEADD(s,0,DATEADD(mm, DATEDIFF(m,0,GETDATE())-1,0)),'MM/dd/yyyy'));

Declare @endDt as datetime = EOMONTH(@StartDt);

SELECT  useruid, 
    userfullname,
    sum(totaltime)SumTime,
    @StartDt as StartDate, 
    @EndDt as EndDate

FROM Table_1.tbl
WHERE ENTRYDATE between @StartDt  and @EndDt
group by useruid, USERFULLNAME;

我将其插入到另一个表中。通过手动将 Startdt 变量中的 -1 更改为 -2 等等,我没有问题。我想知道是否可以在加载另一个表时动态更改它。

同样,我在加载表格时没有问题。我只是想知道是否有更有效的方法可以做到这一点,因为我必须回到 100 个月。

【问题讨论】:

  • 我不明白 - 您正在过滤月份中的任何一天,然后一次返回 1 个月,但插入到同一个表中。为什么不能一次加载所有 100 个月?

标签: sql sql-server date variables datediff


【解决方案1】:

一种方法是递归 CTE:

with dates as (
      select datefromparts(year(getdate()), month(getdate()), 1) as dte
      union all
      select dateadd(month, -1, dte)
      from dates
      where dte > ?  -- how far back do you want to go?
     )
select t.useruid, t.userfullname, sum(t.totaltime) as SumTime,
       d.dte as StartDate, 
       dateadd(month, 1, d.dte) as EndDate
from dates d JOIN
     Table_1.tbl t
     on t.ENTRYDATE >= d.dte AND
        t.ENTRYDATE < dateadd(month, 1, d.dte) 
group by t.useruid, t.USERFULLNAME, d.dte;

您不需要(显式)循环或游标。

注意:出于某种原因,您似乎从日期中减去了一秒。我不明白为什么。对于结束日期,您可能需要此逻辑,但最好使用 on 子句中的不等式(例如,您不必担心毫秒)。

【讨论】:

  • 非常感谢戈登,这很好用。我想我知道我的 CTE 哪里出了问题。我只需要做一个小调整。这目前的结束日期为下个月的第一天。我需要结束日期是开始日期月份的最后一天。我将 dateadd(month, 1, d.dte) 作为 EndDate 更改为 EOMONTH(dte) 作为 EndDate。
  • 这真的没有任何意义 - 你似乎不需要每个月都在那个范围内,你通过这个而不是仅仅过滤 100 个月的范围来实现什么?
  • @mcedave 。 . .你有理由不接受这个答案吗?这对我来说似乎是最好的解决方案。
【解决方案2】:

您可以使用动态 SQL 动态编写 @StartDt 声明语句。

我将您的代码放在将运行 100 次的 while 循环中。 (回到 100 个月):

declare @int int = 0
while @int > -100
begin
set @int= @int -1
declare @str varchar(max)
set @str = 'declare @StartDt as datetime = (SELECT FORMAT(DATEADD(s,0,DATEADD(mm, DATEDIFF(m,0,GETDATE())'+cast(@int as varchar(10))+',0)),''MM/dd/yyyy''))'
execute (@str)

Declare @endDt as datetime = EOMONTH(@StartDt)

SELECT  useruid, 
    userfullname,
    sum(totaltime)SumTime,
    @StartDt as StartDate, 
    @EndDt as EndDate

FROM Table_1.tbl
WHERE ENTRYDATE between @StartDt  and @EndDt
group by useruid, USERFULLNAME
end

【讨论】:

  • 也谢谢你 Gen Wan,我的建议也奏效了
  • @mcedave 欢迎您。递归 CTE 解决方案比我的要好得多。 (这就是为什么我投票赞成戈登的答案)。但我希望我的解决方案能给你一些新的想法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-27
  • 1970-01-01
  • 2012-04-25
相关资源
最近更新 更多