-3

我在一张桌子上得到了这个:

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

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

我需要知道如何计算两个日期之间月份的小时数。

例如,如果范围日期是2013-02-012013-06-01

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

3 回答 3

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 是查找两个日期之间的间隔,第二个 CTE 使用ROW_NUMBERJOIN在实际表上查找每个月的小时数。最后,只求和WHERE RN=1

SQLFiddle 演示

于 2013-07-19T13:23:29.183 回答
1

所以这里的问题实际上是双重的。首先,我们需要对其进行规范化,以便得到实际的month,hourPermonth 元组。我们需要在第 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')
于 2013-07-19T12:57:23.823 回答
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;
于 2013-07-19T13:26:03.837 回答