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
Related
I have a table that holds vehicle activity data. There is a start date and end date columns in the table. I wish to construct a query that will show the amount of time in minutes that each vehicle is active or working on a particular day. My problem is that the time between the start date and end date may span a number of days.
Example:
dwVehicleIDFK StartDate EndDate Minutes HrsMins
731 18/09/2019 08:00 18/09/2019 13:00 300 05:00
797 18/09/2019 08:00 18/09/2019 12:00 240 04:00
687 17/09/2019 16:00 17/09/2019 21:00 300 05:00
826 17/09/2019 16:00 17/09/2019 21:00 300 05:00
734 18/09/2019 10:00 18/09/2019 15:30 330 05:30
843 18/09/2019 14:00 18/09/2019 18:00 240 04:00
662 18/09/2019 09:00 18/09/2019 14:00 300 05:00
662 17/09/2019 09:00 17/09/2019 14:00 300 05:00
662 16/09/2019 09:00 16/09/2019 14:00 300 05:00
817 18/09/2019 14:00 19/09/2019 08:00 1080 18:00
In the data above the vehicle with the ID of 817 extends over two days. How would I get the query to return the time period for the 18/09 only or up until midnight on the 18/09?
The query to return the data above:
Select
dwVehicleIDFK,
StartDate,
EndDate,
DATEDIFF(MINUTE, Convert(DateTime, StartDate, 103),
Convert(DateTime, EndDate, 103)) as Minutes,
CONVERT(varchar(5), DATEADD(minute, DATEDIFF(minute,
Convert(DateTime, StartDate, 103),
Convert(DateTime, EndDate, 103)), 0), 114) as HrsMins
from
VehHistory
Assume you loaded the data for the specified date #Day and converted the start/end date to datetime in temp table #temp:
Select
dwVehicleIDFK,
StartDate,
EndDate,
DATEDIFF(MINUTE, CASE WHEN StartDate<#Day THEN #Day ELSE StartDate END,
CASE WHEN EndDate>DATEADD(DAY,1,#Day) THEN DATEADD(DAY,1,#Day) ELSE EndDate END) AS UsedMinutes
from #temp;
Sql Fiddle Example
I have this result table
Id Hours
----- -----
1 09:00
2 09:30
3 10:00
4 10:30
5 11:00
6 11:30
7 12:00
8 12:30
9 13:00
10 13:30
11 14:00
12 14:30
13 15:00
14 15:30
15 16:00
16 16:30
17 17:00
18 17:30
19 18:00
I need to get the total sum hours, for example from 09:00 to 18:00 there is a total of :
9
hours, I need to get this sum of hours
Your table schema hour is varchar, you need to cast as time, then do the calculation
SELECT datediff(hour,min(cast(hour as time)),max(cast(hour as time)))
FROM Timetable
sqlfiddle
NOTE
I would suggest your hour column as datetime or time instead of varchar. because hour column intention is time.
EDIT
If your time is 9:00 to 17:30, you can try to use datediff minute to get the total diff minutes then divide 60 to get hours.
SELECT datediff(minute,min(cast(hour as time)),max(cast(hour as time))) / CAST(60 as float)
FROM Timetable
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=6e005cdfad4eca3ff7c4c92ef14cc9c7
use datediff function
select datediff(hour,min(h),max(h)) from
(
select CAST(hour AS TIME) as h from Timetable
) as t
strongly disagreed to put time value in varchar ,so it is better change your data type from varchar to time
declare #a time = '13:00',#b time = '17:30' --- Here you can give time, what you need.
select distinct convert(varchar(20)
, datediff(MINUTE,#a,#b) / 60)
+ ':' +
convert(varchar(20), datediff(MINUTE,#a,#b) % 60)
from #Timetable
where hour in (#a,#b)
For your SQL Fiddle Sample Data.
Obviously, you need to use datediff(). However, you should be doing the datediff() in minutes or seconds and then converting to hours:
SELECT datediff(minute, min(cast(hour as time)), max(cast(hour as time))) / 60.0
FROM Timetable;
This will handle the case where the number of hours is not an exact number of hours.
I would like to generate a list of half an hour interval. Any suggestion would be very helpful. I tried this and did not work. Thank you
WITH cte
AS (select convert(varchar, DATEADD(Day, 0, DATEDIFF(Day, 0, GetDate())), 108) AS Today
UNION ALL
SELECT dateadd(MINUTE, 30, Today) AS Today
FROM cte
WHERE dateadd(MINUTE, 30,Today) < (select convert(varchar, DATEADD(Day, 1, DATEDIFF(Day, 0, GetDate())), 108))
)
SELECT*
FROM cte
To get:
0:00
0:30
1:00
1:30
2:00
2:30
3:00
3:30
4:00
4:30
5:00
5:30
6:00
6:30
7:00
7:30
8:00
8:30
9:00
9: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
18:30
19:00
19:30
20:00
20:30
21:00
21:30
22:00
22:30
23:00
23:30
0:00
You can't convert the time to a VARCHAR and then use DATETIME functions on it, you need to keep it as a DATETIME throughout the recursive portion:
;WITH cte AS (SELECT DATEADD(day, 0, DATEDIFF(day, 0, GETDATE())) dt
UNION ALL
SELECT DATEADD(MINUTE, 30, dt) AS dt
FROM cte
WHERE dt < DATEADD(day,1,GETDATE())
)
SELECT CONVERT(VARCHAR(12),dt, 108)
FROM cte
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)
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.