I'm having difficulty with calculating remaining days from hours being distributed over a date range within a given time period. For this example, the time period would be 2013-11-01 through 2013-05-01 (it will always be a 6 month period).
The calendar
table has a 30 year set. 1 Value of 1
for weekday
indicates Monday - Friday.
Setup
CREATE TABLE #calendar (
[d] date PRIMARY KEY,
[weekday] tinyint DEFAULT 0,
);
INSERT INTO #calendar ([d]) VALUES
('2006-01-01', 0),
...
('2013-01-01', 1),
('2013-01-02', 1),
('2013-01-03', 1),
...
('2014-12-28', 0),
('2014-12-29', 1),
('2014-12-30', 1),
('2014-12-31', 1),
...
('2035-12-31', 1);
CREATE TABLE #tasks (
[task] int PRIMARY KEY,
[begin] date,
[end] date,
[hours] decimal(6,3)
);
INSERT INTO #tasks ([task], [begin], [end], [hours]) VALUES
(1, '2013-11-05', '2013-11-05', 5.0),
(2, '2013-10-01', '2013-11-15', 2.0),
(3, '2013-11-15', '2013-12-31', 80.0),
(4, '2013-05-01', '2013-12-04', 2.0),
(5, '2013-07-01', '2013-11-27', 15),
(6, '2013-11-01', '2013-12-10', 40),
(7, '2013-07-01', '2013-08-01', 50.0),
(8, '2014-06-01', '2014-07-01', 10.0);
Part 1
Getting the total weekdays for the tasks:
DECLARE @periodStart date, @periodEnd date;
SET @periodStart = '2013-11-01';
SET @periodEnd = '2014-05-01';
SELECT a.[task], a.[begin], a.[end], a.[hours],
(SELECT SUM([weekday])
FROM #calendar
WHERE [d] BETWEEN a.[begin] AND a.[end]) AS weekdays
FROM #tasks a
WHERE (a.[begin] < @periodStart AND a.[end] > @periodEnd)
OR (a.[begin] >= @periodStart AND a.[end] < @periodEnd)
OR (a.[begin] < @periodEnd AND a.[end] > @periodStart)
Result
task begin end hours weekdays ----------- ---------- ---------- ------- -------- 1 2013-11-05 2013-11-05 5.000 1 2 2013-10-01 2013-11-15 2.000 34 3 2013-11-15 2013-12-31 80.000 33 4 2013-05-01 2013-12-04 2.000 156 5 2013-07-01 2013-11-27 15.000 108 6 2013-11-01 2013-12-10 40.000 28
Part 2
Getting the workdays for the time period:
DECLARE @periodStart date, @periodEnd date;
SET @periodStart = '2013-11-01';
SET @periodEnd = '2014-05-01';
SELECT a.[task], a.[begin], a.[end], a.[hours],
(SELECT SUM([weekday])
FROM #calendar
WHERE [d] BETWEEN a.[begin] AND a.[end]) AS weekdays,
m1.weekdays AS m1wd,
m2.weekdays AS m2wd,
m3.weekdays AS m3wd,
m4.weekdays AS m4wd,
m5.weekdays AS m5wd,
m6.weekdays AS m6wd
FROM #tasks a
CROSS JOIN
-- Month 1 Weekdays
(SELECT CAST(SUM([weekday]) AS decimal(3,1)) AS weekdays FROM #calendar
WHERE [d] BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, 0, @periodStart)+1, 0)
AND DATEADD(MONTH, DATEDIFF(MONTH, 0, @periodStart)+2, -1)) m1
CROSS JOIN
-- Month 2 Weekdays
(SELECT CAST(SUM([weekday]) AS decimal(3,1)) AS weekdays FROM #calendar
WHERE [d] BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, 0, @periodStart)+2, 0)
AND DATEADD(MONTH, DATEDIFF(MONTH, 0, @periodStart)+3, -1)) m2
CROSS JOIN
-- Month 3 Weekdays
(SELECT CAST(SUM([weekday]) AS decimal(3,1)) AS weekdays FROM #calendar
WHERE [d] BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, 0, @periodStart)+3, 0)
AND DATEADD(MONTH, DATEDIFF(MONTH, 0, @periodStart)+4, -1)) m3
CROSS JOIN
-- Month 4 Weekdays
(SELECT CAST(SUM([weekday]) AS decimal(3,1)) AS weekdays FROM #calendar
WHERE [d] BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, 0, @periodStart)+4, 0)
AND DATEADD(MONTH, DATEDIFF(MONTH, 0, @periodStart)+5, -1)) m4
CROSS JOIN
-- Month 5 Weekdays
(SELECT CAST(SUM([weekday]) AS decimal(3,1)) AS weekdays FROM #calendar
WHERE [d] BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, 0, @periodStart)+5, 0)
AND DATEADD(MONTH, DATEDIFF(MONTH, 0, @periodStart)+6, -1)) m5
CROSS JOIN
-- Month 6 Weekdays
(SELECT CAST(SUM([weekday]) AS decimal(3,1)) AS weekdays FROM #calendar
WHERE [d] BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, 0, @periodStart)+6, 0)
AND DATEADD(MONTH, DATEDIFF(MONTH, 0, @periodStart)+7, -1)) m6
WHERE (a.[begin] < @periodStart AND a.[end] > @periodEnd)
OR (a.[begin] >= @periodStart AND a.[end] < @periodEnd)
OR (a.[begin] < @periodEnd AND a.[end] > @periodStart)
Result
task begin end hours weekdays m1wd m2wd m3wd m4wd m5wd m6wd ------ ---------- ---------- ------- ----------- ----- ----- ----- ----- ----- ----- 1 2013-11-05 2013-11-05 5.000 1 22.0 23.0 20.0 21.0 22.0 22.0 2 2013-10-01 2013-11-15 2.000 34 22.0 23.0 20.0 21.0 22.0 22.0 3 2013-11-15 2013-12-31 80.000 33 22.0 23.0 20.0 21.0 22.0 22.0 4 2013-05-01 2013-12-04 2.000 156 22.0 23.0 20.0 21.0 22.0 22.0 5 2013-07-01 2013-11-27 15.000 108 22.0 23.0 20.0 21.0 22.0 22.0 6 2013-11-01 2013-12-10 40.000 28 22.0 23.0 20.0 21.0 22.0 22.0
Problem
Since each task can start/end at different times, how do I calculate and distribute the hours over the remaining days in the months? In part 2, would it be easier to just return a table between the period dates with the workdays and then pivot it?
Desired Result
task begin end hours weekdays m1h m2h ... m6h ------ ---------- ---------- ------- ----------- -------- -------- ----- --- 1 2013-11-05 2013-11-05 5.000 1 5 2 2013-10-01 2013-11-15 2.000 34 0.647059 3 2013-11-15 2013-12-31 80.000 33 26.66667 53.33333 4 2013-05-01 2013-12-04 2.000 156 0.269231 0.038462 5 2013-07-01 2013-11-27 15.000 108 2.638889 6 2013-11-01 2013-12-10 40.000 28 30 10