可以通过加入数字列表来还原该日期范围。
master..spt_values 可以用于此。
要将 [小时] 除以 datediff,首先将其转换为浮点数,然后通过舍入截断为 2 位小数。
select t.EmployeeID,
dateadd(d, v.number, t.StartDate) as StartDate,
dateadd(d, v.number+1, t.StartDate) as EndDate,
t.DivHours as [Hours]
from (
select EmployeeID, StartDate, EndDate,
round(cast([Hours] as float)/datediff(d, StartDate, EndDate),2,1) as DivHours
from myTable
where EndDate > StartDate
) t
join master..spt_values v
on (v.type='P' and v.number >= 0 and v.number < datediff(d, t.StartDate, t.EndDate));
给予:
EmployeeID StartDate EndDate Hours
1 2016-07-01 2016-07-02 2,85
1 2016-07-02 2016-07-03 2,85
1 2016-07-03 2016-07-04 2,85
1 2016-07-04 2016-07-05 2,85
1 2016-07-05 2016-07-06 2,85
1 2016-07-06 2016-07-07 2,85
1 2016-07-07 2016-07-08 2,85
2 2016-07-04 2016-07-05 5
2 2016-07-05 2016-07-06 5
3 2016-07-02 2016-07-03 13
但是,只有当 datediff 低于 2047 时,这才有效。
因为 2047 是您从该系统表中获得的最大数字。
但这仍然是超过 5 年的日期范围。
但是,如果您在该表中有更大的范围。
然后,您可以生成一个包含更多数字的表格。
此示例将 1000000 个数字放入表变量中:
DECLARE @Numbers TABLE (num int primary key);
-- Who dares to claim that cross joins are always useless?
WITH d AS (select n from (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9))q(n))
insert into @Numbers (num)
select (d6.n*100000+d5.n*10000+d4.n*1000+d3.n*100+d2.n*10+d1.n) as num
from d d1, d d2, d d3, d d4, d d5, d d6;
select count(*) as total, min(num) as min_num, max(num) as max_num from @Numbers;
您也可以为此使用递归。
但如果您想添加额外的列,这种方法有点麻烦。
要从 myTable 添加更多列,您可以在 EmployeeID 上将 myTable 加入 R。
WITH R (EmployeeID, StartDate, EndDate, FinalDate, [Hours]) AS
(
SELECT EmployeeID, StartDate, dateadd(d, 1, StartDate),
EndDate as FinalDate,
round(cast([Hours] as float)/datediff(d, StartDate, EndDate),2,1)
from myTable
where StartDate < EndDate
UNION ALL
SELECT EmployeeID, dateadd(d, 1, StartDate), dateadd(d, 2, StartDate),
FinalDate, [Hours]
FROM R WHERE dateadd(d, 1, StartDate) < FinalDate
)
SELECT EmployeeID, StartDate, EndDate, [Hours]
FROM R
ORDER BY EmployeeID, StartDate, EndDate;
如果分段小时数的总和仍需要等于原始小时数?
然后它变得稍微复杂一些。
declare @myTable TABLE (EmployeeID int, StartDate date, EndDate date, [Hours] int);
insert into @myTable values
(0,'2016-1-1','2016-1-4',10),
(1,'2016-1-1','2016-1-8',20);
WITH R (EmployeeID, StartDate, EndDate, FinalDate, [Hours], RemainingHours) AS
(
SELECT EmployeeID,
StartDate,
dateadd(d, 1, StartDate),
EndDate,
round(cast([Hours] as float)/datediff(d, StartDate, EndDate),2,1),
round(cast([Hours] as float),2,1)
from @myTable
where StartDate < EndDate
UNION ALL
SELECT EmployeeID,
dateadd(d, 1, StartDate),
dateadd(d, 1, EndDate),
FinalDate,
(case when dateadd(d, 1, EndDate) < FinalDate then [Hours] else (RemainingHours - [Hours]) end),
(RemainingHours - [Hours])
FROM R WHERE EndDate < FinalDate
)
SELECT EmployeeID, StartDate, EndDate, [Hours]
FROM R
ORDER BY EmployeeID, StartDate, EndDate;