Sql server 在SQL Server中为两个日期之间的每一天添加一行,以小时为单位

Sql server 在SQL Server中为两个日期之间的每一天添加一行,以小时为单位,sql-server,Sql Server,起始数据: 预期结果如下: 因此,它计算了StartDateTime结束前的小时数,如果EndDateTime大于StartDateTime的一天结束时间。然后,它计算出,在这两天之间的每一天,24小时可能会延长很多天。然后当它到达EndDateTime时,它计算从午夜早晨到EndDateTime的时间 我读到,我可能需要使用递归CTE,但我没有任何递归的经验,我很挣扎。这可能会很棘手,但我想可以使用所谓的数字表来解决,即只有一列填充了数字序列的表。在我们的例子中,是基于0的序列 这里的技巧是获

起始数据:

预期结果如下:

因此,它计算了StartDateTime结束前的小时数,如果EndDateTime大于StartDateTime的一天结束时间。然后,它计算出,在这两天之间的每一天,24小时可能会延长很多天。然后当它到达EndDateTime时,它计算从午夜早晨到EndDateTime的时间


我读到,我可能需要使用递归CTE,但我没有任何递归的经验,我很挣扎。

这可能会很棘手,但我想可以使用所谓的数字表来解决,即只有一列填充了数字序列的表。在我们的例子中,是基于0的序列

这里的技巧是获取开始和结束日期时间之间的天数。在数据表和数字表之间的联接中使用的此值将为每天的间隔创建所需的额外行

当然,我们还必须在CTE中正确设置每天间隔案例术语的开始和结束日期时间

然后我们得到每天间隔的分钟数,然后除以60得到正确的十进制值

希望这有帮助

让我们看看代码:

-- input data
DECLARE @v_Dates TABLE
(
    id varchar(20),
    StartDateTime SMALLDATETIME,
    EndDateTime SMALLDATETIME
)

INSERT INTO @v_Dates (id, StartDateTime, EndDateTime)
VALUES ('example 1', '02-17-2019 0:45', '02-19-19 12:30'),
('example 2', '02-21-2019 18:00', '02-22-19 12:15'),
('example 3', '02-22-2019 20:15', '02-22-19 20:30');


-- so called Number table which holds numbers 0 - 9999 in this case 
DECLARE @v_Numbers TABLE
(
  Number INT
);

-- populating the number table
INSERT INTO @v_Numbers
SELECT TOP 10000 ROW_NUMBER() OVER(ORDER by t1.number) - 1 as Number
FROM master..spt_values t1 
CROSS JOIN master..spt_values t2

-- we parse the dates into the per day intervals
;WITH IntervalsParsed(id, StartDateTime, EndDateTime, Number, IntervalStartDateTime, IntervalEndDateTime) AS
(
SELECT id
,StartDateTime
,EndDateTime
,Number
, InervalStartDateTime = CASE
                            WHEN D.StartDateTime > DATEADD(day, DATEDIFF(day, 0, D.StartDateTime), N.Number) THEN D.StartDateTime
                            ELSE DATEADD(day, DATEDIFF(day, 0, D.StartDateTime), N.Number)
                        END
, IntervalEndDateTime = CASE 
                            WHEN D.EndDateTime < DATEADD(day, DATEDIFF(day, 0, D.StartDateTime), N.Number + 1) THEN D.EndDateTime
                            ELSE DATEADD(day, DATEDIFF(day, 0, D.StartDateTime), N.Number + 1)
                        END

FROM @v_Dates D
--this join basically creates the needed number of rows 
INNER JOIN @v_Numbers N ON DATEDIFF(day, D.StartDateTime, D.EndDateTime) + 1 > N.Number
)
-- final select
SELECT id
, StartDateTime
, EndDateTime
, IntervalStartDateTime
, IntervalEndDateTime
, Number
, DecimalValue = CAST( DATEDIFF(minute, IntervalStartDateTime, IntervalEndDateTime) AS DECIMAL)/60

FROM IntervalsParsed
ORDER BY id, Number

另一个选择是一个与交叉应用相协调的临时理货表

范例

返回


这可能有点复杂,但这里有一种使用递归cte获取输出的方法。只要开始日期小于列的结束日期,就可以将开始日期添加为一天。还声明了一个静态值,以确保我们可以得到24小时的差异

-创建一个表

Select 'example1' exm, '2019-02-17 00:45:00' startdate, '2019-02-19 12:30:00' Enddate into #temp union all 

Select 'example2' exm, '2019-02-21 18:00:00' startdate, '2019-02-22 12:15:00' Enddate  union all 
Select 'example3' exm, '2019-02-22 20:15:00' startdate, '2019-02-22 20:30:00' Enddate  

 Declare @datevalue time  = '23:59:59' 

  ;with cte as (select exm, startdate, enddate, case when datediff(day, startdate, enddate) = 0 then datediff(SECOND, startdate, enddate) 
 when datediff(day, startdate, enddate)>0 then  
 datediff(SECOND, cast(startdate as time), @datevalue)    
 end as Hoursn,   cast(dateadd(day, 1,cast(startdate as date)) as smalldatetime)   valueforhours    from #temp 
 union all 
 select   exm, startdate, enddate, case when datediff(day, valueforhours, enddate) = 0 then datediff(SECOND, valueforhours, enddate) 
 when datediff(day, valueforhours, enddate)>0 then  datediff(SECOND, cast(valueforhours as time), @datevalue) end as Hoursn,  case when datediff(day,valueforhours, enddate) > 0 then dateadd(day,1,valueforhours) end    as valueforhours 
 from cte 
 where  
  valueforhours <= cast(enddate as date)
 ) 
 select exm, startdate, Enddate,  round(Hoursn*1.0/3600,2)  as [hours]  from cte 
 order by exm

Stackoverflow不是一个代码编写服务-你需要尝试一些东西,然后就你尝试过的代码寻求帮助。我尝试了几种不同的解决方案,但我就是无法开始工作。这就是我请求帮助的原因。我真的不认为向我展示几个失败的尝试会对我有多大帮助。这完全符合需要。谢谢你的帮助!
Select 'example1' exm, '2019-02-17 00:45:00' startdate, '2019-02-19 12:30:00' Enddate into #temp union all 

Select 'example2' exm, '2019-02-21 18:00:00' startdate, '2019-02-22 12:15:00' Enddate  union all 
Select 'example3' exm, '2019-02-22 20:15:00' startdate, '2019-02-22 20:30:00' Enddate  

 Declare @datevalue time  = '23:59:59' 

  ;with cte as (select exm, startdate, enddate, case when datediff(day, startdate, enddate) = 0 then datediff(SECOND, startdate, enddate) 
 when datediff(day, startdate, enddate)>0 then  
 datediff(SECOND, cast(startdate as time), @datevalue)    
 end as Hoursn,   cast(dateadd(day, 1,cast(startdate as date)) as smalldatetime)   valueforhours    from #temp 
 union all 
 select   exm, startdate, enddate, case when datediff(day, valueforhours, enddate) = 0 then datediff(SECOND, valueforhours, enddate) 
 when datediff(day, valueforhours, enddate)>0 then  datediff(SECOND, cast(valueforhours as time), @datevalue) end as Hoursn,  case when datediff(day,valueforhours, enddate) > 0 then dateadd(day,1,valueforhours) end    as valueforhours 
 from cte 
 where  
  valueforhours <= cast(enddate as date)
 ) 
 select exm, startdate, Enddate,  round(Hoursn*1.0/3600,2)  as [hours]  from cte 
 order by exm
  exm          startdate             Enddate         hours
example1    2019-02-17 00:45:00 2019-02-19 12:30:00 23.250000
example1    2019-02-17 00:45:00 2019-02-19 12:30:00 24.000000
example1    2019-02-17 00:45:00 2019-02-19 12:30:00 12.500000
example2    2019-02-21 18:00:00 2019-02-22 12:15:00 6.000000
example2    2019-02-21 18:00:00 2019-02-22 12:15:00 12.250000
example3    2019-02-22 20:15:00 2019-02-22 20:30:00 0.250000