Here's a different approach that doesn't rely on loops or additional tables, however it does touch the source table twice. (You'll have to replace dbo.aTable
with the name of your actual table, and add where clauses where commented below if you want to filter.)
DECLARE @i INT = 30; -- interval in minutes
DECLARE @ft SMALLDATETIME, @lt SMALLDATETIME;
SELECT @ft = MIN([Start Time]), @lt = MAX([End Time]) FROM dbo.aTable -- WHERE?;
;WITH d1(dt) AS
(
SELECT TOP (DATEDIFF(MINUTE,@ft,@lt)/@i+2)
DATEADD(MINUTE,DATEDIFF(MINUTE,0,DATEADD(MINUTE,@i*(ROW_NUMBER()
OVER (ORDER BY [object_id])-1),@ft))/@i*@i,0)
FROM sys.all_columns
), d2(s,e) AS (SELECT dt,DATEADD(MINUTE,@i,dt) FROM d1
), t AS
(
SELECT [User],[Start Time],[End Time],
StartInterval = DATEADD(MINUTE, DATEDIFF(MINUTE, 0, [Start Time])/@i*@i, 0),
EndInterval = DATEADD(MINUTE, DATEDIFF(MINUTE, 0, [End Time])/@i*@i, 0)
FROM dbo.aTable -- WHERE?
),
n AS
(
SELECT d2.s, d2.e, [User], [Start Time], [End Time],
sr = CASE WHEN [Start Time] >= d2.s AND [Start Time] < d2.e THEN 1 END,
er = CASE WHEN [End Time] > d2.s AND [End Time] <= d2.e THEN 1 END
FROM d2 INNER JOIN t ON d2.s BETWEEN t.StartInterval AND t.EndInterval
)
SELECT [Interval From] = s, [Interval To] = e, [User],
[Elapsed Time] = CASE WHEN sr = 1 OR er = 1 THEN
DATEDIFF(MINUTE, CASE WHEN sr = 1 THEN [Start Time] ELSE s END,
CASE WHEN er = 1 THEN [End Time] ELSE e END)
WHEN s = [End Time] THEN 0 ELSE @i END
FROM n ORDER BY [User], [Interval From];
I realize this has been answered before on Stack Overflow. It got me going in the right direction.
I now realize I should add the actual time stamp of the leave to my Start and End Dates and do a simple compare. I wish I had figured this out months ago; it would have saved me much pain and suffering.
For anyone in the future who has a similar issue:
- My new
StartDate
will be recorded as 08/22/2015 09:00.000
instead of 08/22/2015 00:00.000
- The
EndDate
will be 8/23/2015 13:00:00.000
I can then compare as per the linked answer:
(
(@Start > StartDate and @Start < EndDate)
OR (@End > StartDate and @End < EndDate)
OR (@Start < StartDate and @End >EndDate)
)
Best Answer
Let assume by using below input:
And the expected result as:
AND, my script as to do it as below:
Update with new request: single zero between series of 1 will be ignored.