计算2个日期之间的值

时间:2013-07-19 12:54:40

标签: sql sql-server-2008 tsql

我把它放在一张桌子上:

id  dateFrom   hours
1  2013-02-01   6
2  2013-04-01   8

hours表示从该日期开始的一个月内的小时数,有效期至下一条记录。

我需要知道如何在两个日期之间总结月份的小时数

例如,如果范围日期为 2013-02-01 ,则 2013-06-01 :< / p>

6hs for february +
6hs for march +
8hs for april + 
8hs for may +
8hs for june
========
36 hs

3 个答案:

答案 0 :(得分:4)

DECLARE @startDate DATE
DECLARE @endDate DATE

SET @startDate = '20130201'
SET @endDate   = '20130601'

;WITH CTE_Months AS 
(
    SELECT @startDate DT
    UNION ALL
    SELECT DATEADD(MM,1,DT) FROM CTE_Months  
    WHERE DATEADD(MM,1,DT) <= @endDate
)
,CTE_RN AS 
(
    SELECT *, ROW_NUMBER() OVER (PARTITION BY DT ORDER BY dateFrom DESC) RN
    FROM CTE_Months m
    LEFT JOIN Table1 t ON m.DT >= t.dateFrom 
)
SELECT SUM(hours) 
FROM CTE_RN WHERE RN = 1

第一个递归CTE是在两个日期之间找到差距,在实际表格中使用ROW_NUMBERJOIN查找第二个CTE,以查找每个月的小时数。最后,只需加上WHERE RN=1

<强> SQLFiddle DEMO

答案 1 :(得分:1)

所以这个问题实际上是两个问题。首先,我们需要对其进行规范化,以便我们得到实际的月,小时的元组。我们需要在第n行和第n + 1行之间创建月增量,并为它们分别提供原始表的小时值。

我通过使用可以调用或交叉应用参数的内联表值函数来解决它。

完整的测试解决方案:http://sqlfiddle.com/#!6/b7e58/1

该功能的示例代码以及如何调用它:

CREATE FUNCTION dbo.GetSum(@startDate date,@endDate date)
RETURNS TABLE
AS RETURN
(
WITH cte as
(
SELECT @startDate as s
UNION ALL
SELECT DATEADD(month,1,s)
FROM cte WHERE s<@endDate
)
SELECT
SUM(hours) as sumHours
FROM cte
CROSS APPLY (SELECT top 1 h.hours FROM dbo.hourInterval as h WHERE h.startdate <= cte.s order by h.startdate desc) as t
)
GO
SELECT * FROM dbo.GetSum('2013-02-01','2013-06-01')

答案 2 :(得分:1)

我明白了。 hours表示从该日期开始的一个月内的小时数。然后,您希望按月添加内容。

以下使用递归CTE计算每个月的一天。然后它连接到您的表,并选择当前行之前的最新行。最后,它累计了几个小时:

declare @fromdate date = '2013-02-01';
declare @todate date = '2013-06-01';

with months as (
      select @fromdate as thedate
      union all
      select DATEADD(month, 1, thedate)
      from months
      where DATEADD(month, 1, thedate) <= @todate
     ),
     t as (
      select 1 as id, CAST('2013-02-01' as DATE) as datefrom, 6 as hours union all
      select 2, '2013-04-01', 8
     )
select SUM(hours)
from (select t.*, m.thedate, ROW_NUMBER() over (partition by m.thedate order by t.datefrom desc) as seqnum
      from months m join
           t
           on m.thedate >= t.datefrom
     ) t
where seqnum = 1;