基于动态日期在SQL Server中拖动一个月的行

时间:2014-04-17 07:33:44

标签: sql sql-server sql-server-2008 tsql

我在SQL服务器中有一个看起来像这样的表(还有其他字段,但我只关心了2个):

-----------------------------------------
|    DraftDay (int)|  MonthlyFee (money)|
-----------------------------------------
      1                 18.75
      2                 15.25
      2                 15.25
      3                 15.25
      3                 28.12
      4                 15.25
      4                  3.75
      4                 18.19
      5                 12.75
      6                 13.80
      6                 14.25
     ...                 ...
     ...                 ...

我要做的是编写一个将按DraftDay分组并对MonthlyFee字段求和的查询。很简单。但困难之处在于,我需要获得一个月前的日期,再加上一天,从当天开始计算当天的日期。例如,如果今天是2014年4月3日,那么我需要在2014年3月4日和2014年4月3日之间拉出所有日期。我的结果集应如下所示:

3/4/2014         37.19
3/5/2014         12.75
3/6/2014         28.05
 ...              ...
 ...              ...
4/1/2014         18.75
4/2/2014         30.50
4/3/2014         43.37

我创建了这个查询:

SELECT 
    CAST(CAST(DATEPART(MONTH, DATEADD(DAY, 1, DATEADD(MONTH, -1, GETDATE()))) AS VARCHAR(2)) + '/' +
    CAST(CASE WHEN EftDraftDay>28 THEN 28 ELSE EftDraftDay END AS VARCHAR(2)) + '/' +
    CAST(DATEPART(YEAR, DATEADD(DAY, 1, DATEADD(MONTH, -1, GETDATE()))) AS VARCHAR(4)) AS DATETIME) AS DraftDate,
    SUM(MonthlyPayment) AS MonthlyPayment FROM dbo.Advertiser
WHERE IsDeleted=0
    AND IsPaidInFull=0
    AND IsAdvertiserActive=1
    AND EftDraftDay>0
    AND (CAST(CAST(DATEPART(MONTH, DATEADD(DAY, 1, DATEADD(MONTH, -1, GETDATE()))) AS VARCHAR(2)) + '/' +
    CAST(CASE WHEN EftDraftDay>28 THEN 28 ELSE EftDraftDay END AS VARCHAR(2)) + '/' +
    CAST(DATEPART(YEAR, DATEADD(DAY, 1, DATEADD(MONTH, -1, GETDATE()))) AS VARCHAR(4)) AS DATETIME)) >=
    CAST(CAST(DATEPART(MONTH, DATEADD(DAY, 1, DATEADD(MONTH, -1, GETDATE()))) AS VARCHAR(2)) + '/' +
    CAST(DATEPART(DAY, DATEADD(DAY, 1, DATEADD(MONTH, -1, GETDATE()))) AS VARCHAR(2)) + '/' +
    CAST(DATEPART(YEAR, DATEADD(DAY, 1, DATEADD(MONTH, -1, GETDATE()))) AS VARCHAR(4)) AS DATETIME)
GROUP BY 
    CAST(CAST(DATEPART(MONTH, DATEADD(DAY, 1, DATEADD(MONTH, -1, GETDATE()))) AS VARCHAR(2)) + '/' +
    CAST(CASE WHEN EftDraftDay>28 THEN 28 ELSE EftDraftDay END AS VARCHAR(2)) + '/' +
    CAST(DATEPART(YEAR, DATEADD(DAY, 1, DATEADD(MONTH, -1, GETDATE()))) AS VARCHAR(4)) AS DATETIME)

因为今天的日期是2014年4月17日,所以我应该从2014年3月18日到2014年4月17日收到结果。我得到的结果仅从2014年3月18日至2014年3月28日。我怎样才能将2014年4月1日到2014年4月17日添加到我的结果集中?我想过UNION,但那些似乎与GROUP BY的效果不佳。

在试图弄清楚并查看我的查询之后,我想我完全是在设计这个。对于这么简单的事情,我的查询看起来很复杂。有人可以帮我解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

试试这个:

declare @lastmonth date = convert(date,dateadd(day,1,dateadd(month,-1,getdate())))
declare @thismonth date = convert(date,getdate())

select 
case 
when draftday < datepart(day,@thismonth) 
then convert(date, cast(datepart(yyyy,@thismonth) as varchar) +    right('00'+cast(datepart(MM,@thismonth) as varchar),2) + right('00'+cast(cast(draftday as  varchar) as varchar),2))
else convert(date, cast(datepart(yyyy,@lastmonth) as varchar) + right('00'+cast(datepart(MM,@lastmonth) as varchar),2) + right('00'+cast(cast(draftday as varchar) as varchar),2))
end,
sum(monthlyfee) from tbl
group by draftday

这会将当天之前的天数视为属于当月,而其他人则是从上个月开始,然后总结。请告诉我这是否符合您的期望。

答案 1 :(得分:1)

我使用日历表(http://www.dbdelta.com/calendar-table-and-datetime-functions/),如下所示:

declare @d datetime ='20140403'

select c.CalendarDate, sum(#t.MonthlyFee)
from calendar c
left join #t on c.CalendarDay = #t.DraftDay
where CalendarDate between dateadd(month, -1, @d)+1 and @d
group by c.CalendarDate