Club overlapping time slots together in SQL Server - sql

I have a table which has records of overlapping time-slots.
E.g.: Calendar(Id int, StartDate datetime, EndDate datetime, EventTitle nvarchar(100), ...)
The records would be like
01/20/2011 08:15 AM --- 01/20/2011 08:40 AM
01/20/2011 08:20 AM --- 01/20/2011 08:55 AM
01/20/2011 12:30 PM --- 01/20/2011 01:15 PM
01/20/2011 02:00 PM --- 01/20/2011 02:45 PM
01/20/2011 02:15 PM --- 01/20/2011 02:30 PM
01/21/2011 12:30 PM --- 01/21/2011 01:15 PM
.......
.......
The table represents the event schedule of a person
I want to club the overlapping slots together to give:
01/20/2011 08:15 AM --- 01/20/2011 08:55 AM
01/20/2011 12:30 PM --- 01/20/2011 01:15 PM
01/20/2011 02:00 PM --- 01/20/2011 02:45 PM
01/21/2011 12:30 PM --- 01/21/2011 01:15 PM
...
...
I am stuck at this part of the problem... (I removed my code that I pasted here, as it looks mangled. I am using stackoverflow for the first time.)
Part of my actual requirement is to find a time slot [t] (let's say 25 minutes) between two given dates, which I can accommodate into the schedule. [t] has to be found between 8:00 AM and 05:00 PM on any day.

This is an interesting question.
For a given date, lets consider the overlaps (I entered all my date times as per yours but for the 1/1/2011):
SELECT dt1.StartTime AS StartOverlap,
CASE
WHEN dt1.EndTime > dt2.EndTime THEN dt1.EndTime
ELSE dt2.EndTime
END AS EndOverlap
FROM datetimetest dt1, datetimetest dt2
WHERE dt2.StartTime > dt1.StartTime
AND dt2.StartTime < dt1.EndTime
This gives me:
StartOverlap EndOverlap
01/01/2011 08:15:00 01/01/2011 08:55:00
01/01/2011 14:00:00 01/01/2011 14:45:00
Great, we now know the start and end times we can't use that overlap.
How do we get the other none overlapping times?
I would look at all the time periods that are in the overlapping ranges, and then select out the id's that are not in that date range:
SELECT id
FROM (SELECT dt1.StartTime AS StartOverlap,
CASE
WHEN dt1.EndTime > dt2.EndTime THEN dt1.EndTime
ELSE dt2.EndTime
END AS EndOverlap
FROM datetimetest dt1, datetimetest dt2
WHERE dt2.StartTime > dt1.StartTime
AND dt2.StartTime < dt1.EndTime
) AS Overlaps, datetimetest dtt
WHERE dtt.StartTime >= Overlaps.StartOverlap
AND dtt.EndTime <= Overlaps.EndOverlap
This gives me a list of all the ids that are in the overlaps. I then just select all of the entries that are NOT in the overlaps:
SELECT StartTime, EndTime FROM datetimetest
WHERE id NOT IN(
SELECT id
FROM (SELECT dt1.StartTime AS StartOverlap,
CASE
WHEN dt1.EndTime > dt2.EndTime THEN dt1.EndTime
ELSE dt2.EndTime
END AS EndOverlap
FROM datetimetest dt1, datetimetest dt2
WHERE dt2.StartTime > dt1.StartTime
AND dt2.StartTime < dt1.EndTime
) AS Overlaps, datetimetest dtt
WHERE dtt.StartTime >= Overlaps.StartOverlap
AND dtt.EndTime <= Overlaps.EndOverlap)
To give me:
StartTime EndTime
01/01/2011 12:30:00 01/01/2011 13:15:00
I can then union both queries together to give me a list of all used time slots.
As we are effectively cross joining the same table, I would add an additional clause to each query to constrain the date to a single date.

Related

sql missing date query

Having a table with these records:
01-JAN-15 10:00
01-JAN-15 11:00
01-JAN-15 13:00
01-JAN-15 14:00
01-JAN-15 15:00
01-JAN-15 18:00
01-JAN-15 19:00
It's 1h resolution, so in my example 12:00, 16:00 and, 17:00 are missing.
I would like to create an SQL query that returns something like this (missing hour start, and duration):
01-JAN-15 12:00, 01:00
01-JAN)15 16:00, 02:00
Any suggestion?
Assuming your values are datetime values, then you can do something like this:
select t.*,
datediff(hour, datetimecol, next_datetimecol)
from (select t.*,
lead(datetimecol) over (order by datetimecol) as next_datetime
from t
) t
where next_datetimecol is not null and
dateadd(hour, 1, datetimecol) < next_datetimecol;
Depending on your data types and the precision, this might not work exactly. But the idea is basically the same . . . use lead() to get the next value and do some comparisons.

How to generate hours between two hours in SQL Server?

I want to generate a list of hours between to hours with an interval of 30 minutes.
For example an employee enters work at 09:00 and leaves at 18:00, so I want to generate this:
Hours
-----
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
17:00
17:30
18:00
How can I generate this? Thanks.
Well using recursive CTE, you can achieve this result.
Try below query -
DECLARE #timeFrom TIME = '09:00'
DECLARE #timeTo TIME = '18:00'
;with SourceHrs
as
(
select #timeFrom as [Hours]
UNION ALL
SELECT DATEADD(MINUTE, 30, [Hours]) from SourceHrs WHERE [Hours] < #timeTo
)
SELECT CONVERT(VARCHAR(5),Hours,108) FROM SourceHrs
Result
Hours
-------
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
17:00
17:30
18:00
This will give you what you need, using a tally is faster than recursive:
DECLARE #from time = '09:00'
DECLARE #to time = '09:00'
IF #from <= #to
WITH N(N)AS
(SELECT 1 FROM(VALUES(1),(1),(1),(1),(1),(1),(1))M(N)),
tally(N)AS(SELECT ROW_NUMBER()OVER(ORDER BY N.N)FROM N,N a)
SELECT top (datediff(minute, #from, #to)/ 30 + 1 )
LEFT(dateadd(minute, (N - 1 )*30, #from), 5)
FROM tally
You can also try while loop
DECLARE #strattime TIME = '09:00' DECLARE #endtime TIME = '18:00'
CREATE TABLE #tmp_hours( [BetweenHours] VARCHAR(5) )
WHILE #strattime <= #endtime BEGIN INSERT INTO #tmp_hours values(#strattime) SET #strattime = DATEADD(minute,30,#strattime) END
SELECT * FROM #tmp_hours DROP TABLE #tmp_hours

Finding in between which two dates in a column the target date is

Got a table that I am trying to clean up and can't figure out how to find a record where one date falls between two dates in the actual columns
TargetDateTime Location TransferDateTime
01/01/2014 1:00 PM Room 1 01/01/2014 10:00 AM
01/01/2014 1:00 PM Room 2 01/01/2014 12:30 PM
01/01/2014 1:00 PM Room 3 01/01/2014 01:30 PM
01/01/2014 1:00 PM Room 4 01/01/2014 03:00 PM
TransferDateTime marks the time when a person was moved to the room
TargetDateTime marks some event that a person did.
In this example, TargetDateTime is 1:00 PM; therefore the event took place in Room 2 because 1:00 PM falls between 12:30 PM and 1:30 PM.
What would be the best way in SQL to select only that row and ignore the rest?
Thanks a bunch for any suggestions!
Based on your sample data and guessing that you have groups of the same TargetDateTime, the following should do it.
;WITH MyCTE AS
(
SELECT TargetDateTime,
Location,
TransferDateTime
ROW_NUMBER() OVER (PARTITION BY TargetDateTime ORDER BY TransferDateTime) AS rn
FROM TableName
WHERE TransferDateTime >= TargetDateTime
)
SELECT *
FROM MyCTE
WHERE rn = 1

How to count the records per half hour from a period (datetimefrom and datetimeto) field?

I have a table which looks like you can see below:
Id Date ScheduledTimeFrom ScheduledTimeTo ActualTimeFrom ActualTimeTo
1 2013-01-01 1899-12-30 07:00:00 1899-12-30 18:00:00 1899-12-30 07:23:00 1899-12-30 17:15:00
I need to calculate per half hour how many records exists, the output should be like:
Time Actual Count:
7:00 4
7:30 4
8:00 4
8:30 4
9:00 4
9:30 5
10:00 5
10:30 6
11:00 7
11:30 8
12:00 8
12:30 8
13:00 8
13:30 8
14:00 8
14:30 8
15:00 7
15:30 7
16:00 7
16:30 6
17:00 5
17:30 4
18:00 4
I already tried to make a helper table which should hold the times per halfhour. I have joined this helpertable with the table that contains the data and after that I tried to use a group by function but it was not working.
My query was like:
Create table period (timefrom datetime, timeto datetime)
insert into period
select '1899-12-30 07:00:00.000', '1899-12-30 07:30:00.000'
Union all
select '1899-12-30 07:30:00.000', '1899-12-30 08:00:00.000'
select *
from period p left join table1 t on t.ActualTimeFrom < p.timeto and t.ActualTimeTo >=p.timefrom
Grouping this give me no desired result....
Anyone an idea how to come to the result?
P.s. I am using sql server 2005.
After snooping around and testing it on my side, looks like this date function could be the answer:
DATEADD(mi,DATEDIFF(mi,0,YOUR_DATE_COLUMN)/30*30,0)

SQL code for Comparing date fields in different rows and combining the results

I need help for proper Oracle SQL code to combine rows for a crystal reports command object. This is a part of the bigger query I'm working on and got stuck for the past couple of days.
for eg. if the columns are like below
PatId In_time Out_time
151 01/01/2012 07:00:00 am 01/01/2012 10:00:00 am
151 01/01/2012 11:00:00 am 01/02/2012 08:00:00 am
151 01/02/2012 11:00:00 am 01/02/2012 01:00:00 pm
151 01/03/2012 08:00:00 am 01/03/2012 03:00:00 pm
151 01/06/2012 03:30:00 pm 01/09/2012 07:00:00 am
167 01/03/2012 01:30:00 pm 01/09/2012 07:00:00 am
167 01/13/2012 03:30:00 pm 01/14/2012 07:00:00 am
167 01/14/2012 11:30:00 am 01/15/2012 11:30:00 am
167 01/18/2012 12:00:00 pm 01/19/2012 03:00:00 am
Within a PatId, the code should compare the Out_time of one row to the In_time of the next row, and check whether the time gap is greater than 48 hours. If not, then it is considered part of the same visit. I want one result row per PatID & visit, with min(In_time) and max(Out_time). The time span of the visit (result row) itself may be greater than 48 hours.
For this example, for PatId 151 the time difference between the out_time of 1st row and In_time of 2nd row is less than 48 hours. The difference between Out_time of second row and In_time of 3rd row, as well as between the 3rd and 4th rows, is also less than 48 hours. After this the gap between Out_time of the 4th row and In_time of 5th row is greater than 48 hours. The result for PatId 151 should be as below and same for EmpId 167, the chaining should continue until a gap greater than 48 hours is found.
So the result for the above table should be displayed as,
PatId In_time Out_time
151 01/01/2012 07:00:00 am 01/03/2012 03:00:00 pm
151 01/06/2012 03:30:00 pm 01/09/2012 07:00:00 am
167 01/03/2012 01:30:00 pm 01/09/2012 07:00:00 am
167 01/13/2012 03:30:00 pm 01/15/2012 11:30:00 am
167 01/18/2012 12:00:00 pm 01/19/2012 03:00:00 am
I could not get the logic on how to compare and merge rows.
Thanks in Advance, Abhi
General example of subtracting time - copy/paste to see the output. This example will give you differences in hours, minutes, seconds between two dates. The basic formula is (end_date - start_date) * 86400 (number of seconds in 24 hrs)...:
SELECT trunc(mydate / 3600) hr
, trunc(mod(mydate, 3600) / 60) mnt
, trunc(mod(mydate, 3600) / 60 /60) sec
FROM
(
SELECT (to_date('01/03/2012 10:00:00', 'mm/dd/yyyy hh24:mi:ss') -
to_date('01/01/2012 07:00:00', 'mm/dd/yyyy hh24:mi:ss')) * 86400 mydate
FROM dual
)
/
HR | MNT | SEC
---------------
51 | 0 | 0
You need to check your example and logic. I could not understand what needs to be comnpared with what...