SQL Separate hours in Start and EndDate - sql

I'm need a help to create a Query. My problem is I have a StartDate and EndDate and need separate this in blocs of 60 minutes.
DECLARE #STARTDATE AS SMALLDATETIME
DECLARE #ENDDATE AS SMALLDATETIME
SET #STARTDATE = '2012-11-21 11:03:00'
SET #ENDDATE = '2012-11-21 13:04:00'
I need the return:
Hour, Time
11 , 57
12 , 60
13 , 04

You could use a recursive CTE. For example:
declare #startDate datetime = '2012-11-21 22:05:00'
declare #endDate datetime = '2012-11-22 01:06:00'
; with TimeList as
(
select #startDate as dt
union all
select dateadd(hour, 1, dateadd(hour, datediff(hour, 0, dt), 0))
from TimeList
where dateadd(hour, 1, dt) < #endDate
)
select dt
from TimeList
union all
select #endDate
The snippet dateadd(hour, datediff(hour, 0, dt), 0) removes the hours and minutes from a date. It does so by calculating the number of hours since date 0 and then adding that number of hours to date 0.
Live example at SQL Fiddle.

I unsure if i understood you but this will return the hour and minute after your start date at 60 min intervals.
DECLARE #STARTDATE AS SMALLDATETIME
DECLARE #ENDDATE AS SMALLDATETIME
DECLARE #time AS TABLE(id int identity(1,1), [hour] int, [time] int)
SET #STARTDATE = '2012-11-21 11:03:00'
SET #ENDDATE = '2012-11-21 13:04:00'
WHILE #STARTDATE < #ENDDATE
BEGIN
SELECT #STARTDATE = DATEADD(MINUTE,60,#STARTDATE)
INSERT INTO #time (hour,time)
VALUES(DATEPART(HOUR,#STARTDATE),DATEPART(MINUTE,#STARTDATE))
END
SELECT * FROM #time

You coan do it in three pieces. First piece is for the first hour, 60 minus the minute value, 2nd piece is time=60 for all hours between start+1 and end, third piece is end minutes
and then insert them into a temp table, as abstractChaos has done.
Insert into temp table like AbstractChaos:
DECLARE #STARTDATE AS SMALLDATETIME
DECLARE #ENDDATE AS SMALLDATETIME
DECLARE #TIME AS TABLE(id INT IDENTITY(1,1), [HOUR] INT, [TIME] INT)
SET #STARTDATE = '2012-11-21 11:03:00'
SET #ENDDATE = '2012-11-21 13:04:00'
INSERT INTO #TIME (HOUR,TIME)
VALUES (datepart(HOUR,#startdate) ,60 - datepart(MINUTE,#startdate) )
WHILE #STARTDATE < #ENDDATE
BEGIN
SELECT #STARTDATE = DATEADD(MINUTE,60,#STARTDATE)
INSERT INTO #TIME (HOUR,TIME)
VALUES(datepart(HOUR,#STARTDATE) , 60)
END
INSERT INTO #TIME (HOUR,TIME)
VALUES(datepart(HOUR,#enddate) , datepart(MINUTE,#startdate))

Related

Is there an efficient way to break a date range into hours per day?

In SQL Server I am attempting to break a date range into hours per day and have the following bit of code which is OK for a short time frame, but rather inefficient for longer periods of time. Could anyone suggest a more efficient approach?
DECLARE #StartDate datetime = '2015-01-27 07:32:35.000',
#EndDate datetime = '2015-04-29 14:39:35.000',
#TempDate datetime = '';
SET #TempDate = #StartDate;
DECLARE #dateTimeTable TABLE (dt datetime, minCol INT);
WHILE #TempDate < #EndDate
BEGIN
INSERT INTO #dateTimeTable VALUES (CONVERT(date,#TempDate), 1)
SET #TempDate = DATEADD(minute,1,#TempDate)
END
Select dt,
FORMAT(SUM(minCol) / 60.0,'F') as Hours
from #dateTimeTable
GROUP BY dt
Thanks,
Carl
The best way would be to use recursive cte :
DECLARE #StartDate datetime = '2015-01-27 07:32:35.000',
#EndDate datetime = '2015-04-29 14:39:35.000';
WITH cte AS (
SELECT CAST(#StartDate AS DATE) startdate,DATEDIFF(minute, #StartDate, DATEADD(DAY, 1, CAST(#StartDate AS DATE) ) ) / 60.0 hours
UNION ALL
SELECT DATEADD(DAY,1, startdate), DATEDIFF(minute, DATEADD(DAY,1, startdate), CASE WHEN DATEADD(DAY,2, startdate) > #EndDate
THEN #enddate ELSE DATEADD(DAY,2, startdate) END) / 60.0
FROM cte
WHERE startdate <> CAST(#EndDate AS DATE)
)
SELECT * FROM cte
db<>fiddle here

Know what the following SQL code is doing

What does the following code do??
Declare #StartDate datetime; -- figure
Declare #EndDate datetime; -- figure
Declare #CurrentDate datetime
Set #CurrentDate = #StartDate
While #CurrentDate <= #EndDate
Begin
Insert Into dbo.Tbl_Time_Dimension
Values (#CurrentDate,
year(#CurrentDate),
datepart(Quarter, #CurrentDate),
month(#CurrentDate),
datepart(week, #CurrentDate),
day(#CurrentDate))
Select #CurrentDate = DateAdd(dd, 1, #CurrentDate)
End
This code will iterate from #StartDate to #EndDate skipping by day and will insert a row into a table called Tbl_Time_Dimension.
The fields being saved into this table are : Date, Year, Quarter, Month, Week and Day for each date in the date range.
Declare #StartDate datetime; --figure
Declare #EndDate datetime; --figure
Declare #CurrentDate datetime
-- Starts the iterator on #StartDate
Set #CurrentDate=#StartDate
-- Iterates until #EndDate
While #CurrentDate<=#EndDate
Begin
-- Saves data in table
Insert Into dbo.Tbl_Time_Dimension
Values (#CurrentDate, year(#CurrentDate),
datepart(Quarter,#CurrentDate),
month(#CurrentDate),
datepart(week,#CurrentDate),
day(#CurrentDate))
-- Increments the date by 1 day
Select #CurrentDate=DateAdd(dd,1,#CurrentDate)
End
this query gets two date
and for each day between startdate and enddate insert that date into Tbl_Time_Dimension as well as it's month , week , Day and quarter

Displaying the number of valid results for a range of dates

I currently have a table with a creation date and a expiry date. I currently have a sql command to get the number of valid items for a given date.
select
count(id) ,CONVERT(date, getdate())
from
table
where
createDate < getdate() and expDate > getdate()
This returns the count and current date.
Is it possible to wrote a sql query that will return the result for a range of dates, say I if wanted to plot the number of valid items over a range of 15 days?
Thanks!
Try this:
create table #datelist (ValidDateCheck date, ValidResults int)
declare #startdate date = '1/1/2015'
declare #enddate date = '2/1/2015'
declare #interval int = 1 --Use 1 if you want every day between your dates, use 2 if you want every other day, etc.
declare #datecounter date = #startdate
declare #count int
while #datecounter <= #enddate
begin
set #count =
(select count(*)
from Table
where CrtDt <= #datecounter and ExpDt > #datecounter)
insert into #datelist values (#datecounter, #count)
set #datecounter = dateadd(dd, #interval, #datecounter)
end
select * from #datelist order by 1
It loops through all the dates in your range, counting valid results for each one.
Check this,
DECLARE #StartDate DATETIME,
#EndDate DATETIME;
SELECT #StartDate = '20110501'
,#EndDate = '20110801';
SELECT
DATEADD(d, x.number, #StartDate) AS MonthName1
,
x.number
FROM master.dbo.spt_values x
WHERE x.type = 'P'
AND x.number <= DATEDIFF(MONTH, #StartDate, #EndDate);
The above query give the list of dates between 2 dates.
As per your table and question, check this also.
declare #table table(id int,frdt datetime, todt datetime)
insert into #table values (1,GETDATE()-20, GETDATE()-19)
,(2,GETDATE()-9, GETDATE()-8)
,(3,GETDATE()+20, GETDATE()+18)
,(4,GETDATE(), GETDATE()-1)
,(5,GETDATE()-20, GETDATE())
,(6,GETDATE()-10, GETDATE()+10 )
select * from #table
declare #frdt datetime = null , #todt datetime = getdate()-10
select #frdt, #todt,* from #table
where
(#frdt is null or #frdt between frdt and todt)
and
(#todt is null or #todt between frdt and todt)
select #frdt = GETDATE()-15 , #todt = GETDATE()
select #frdt, #todt,* from #table
where
(#frdt is null or #frdt between frdt and todt)
and
(#todt is null or #todt between frdt and todt)

Having issues with dates in SQL

I'm writing a report that needs to collect data each day, between 0900hs and 1700hs.
I thought it would be fine as follows:
cast(convert(char(8),t.trxtime,112)as time)
between CONVERT(VARCHAR(5),getdate(),108) >= '09:00'
and CONVERT(VARCHAR(5),getdate(),108) < '17:00'
....BUT no cigar.
Thank you!!!
Hmmm, you could just use datepart():
where datepart(hour, t.trxtime) between 9 and 16 and
cast(t.trxtime as date) = cast(getdate() as date)
I'm not sure if the date comparison is actually necessary.
You could do something like this (assuming you mean actually for the current date, and not for every date in a range:
declare #startDate datetime
declare #endDate datetime
select #startDate = '2014-11-03 09:00:00',
#endDate = '2014-11-03 17:00:00'
select *
from table
where myDate between #startDate and #endDate
if you did mean between 0900 and 1700 for each day, you could do:
declare #startDate datetime
declare #endDate datetime
select #startDate = '2014-10-03',
#endDate = '2014-11-03' -- note i'm still limiting it to a range of ~1 month
select *
from table
where myDate between #startDate and #endDate
and datepart(hour, myDate) between 9 and 17

Calculate difference between times in results SQL

I have a table with results:
C_EventTime L_TID
20130228162022 27200
20130228162059 27200
How would I calculate difference in seconds between the two?
In the end, I need to calculate all the differences to make a total for the month.
I've tried:
declare #startdt '20130228162022'
declare #enddt '20140101000001'
set #startdt = cast('20130101000001' as datetime)
set #enddt = cast('20140101000001' as datetime)
SELECT DATEDIFF(C_EventTime) FROM tTerminalStateLog
WHERE C_EventTime BETWEEN #startDate and #endDate
and L_TID = 27200
but suspect with my limited SQL knowledge I'm way off! Any help appreciated.
Tx
The strings you are using, don't convert nicely to a valid datetime format.
Credit to http://rdineshkumar.wordpress.com/tag/how-to-convert-yyyymmddhhmmss-to-datetimedatetime-in-sql-server/ for the formula here.
First off, DATEDIFF() takes 3 arguments. The return value, be it seconds, days, etc. Then the start/end dates. Ex DATEDIFF(SS,startdate,enddate) Doc.
Here is a sample on how to convert your two start/end values to a datetime, and calculate the difference between them.
declare #startdt datetime
declare #enddt datetime
select #startdt =
Convert(time,Dateadd(SECOND,
Right('20130228162022',2)/1,
Dateadd(MINUTE,
Right('20130228162022',4)/100,
Dateadd(hour,
Right('20130228162022',6)/10000,
'1900-01-01')))) +
convert(datetime,LEFT('20130228162022',8))
select #enddt =
Convert(time,Dateadd(SECOND,
Right('20140101000001',2)/1,
Dateadd(MINUTE,
Right('20140101000001',4)/100,
Dateadd(hour,
Right('20140101000001',6)/10000,
'1900-01-01')))) +
convert(datetime,LEFT('20140101000001',8))
select #startdt, #enddt
select DATEDIFF(ss, #startdt, #enddt)
However your table shows the values split into separate rows... This makes it slightly more complicated.
Assuming you have 2 results per L_Tid (no more, or this won't work) and you always want to compare the oldest-to-newest date (they'll never write backwards), you could do this:
declare #tTerminalStateLog table (C_EventTime varchar(15), L_Tid INT)
insert into #tTerminalStateLog
select '20130228162022',27200 union all
select '20130228162059',27200
declare #startdt varchar(15), #enddt varchar(15)
set #startdt = '20130228162022'
set #enddt = '20140101000001'
; with datesdata as
(
SELECT Convert(time,Dateadd(SECOND,
Right(C_EventTime,2)/1,
Dateadd(MINUTE,
Right(C_EventTime,4)/100,
Dateadd(hour,
Right(C_EventTime,6)/10000,
'1900-01-01')))) +
convert(datetime,LEFT(C_EventTime,8)) myDate,
L_Tid,
ROW_NUMBER() over(order by C_EventTime) as myID
FROM #tTerminalStateLog
WHERE C_EventTime BETWEEN #startdt and #enddt
and L_Tid=27200
)
select d1.myDate, d2.myDate, DATEDIFF(ss, d1.myDate, d2.myDate) [sec_diff]
from datesdata d1
left outer join datesdata d2
on d1.L_Tid=d2.L_Tid
and d2.myID=2
where d1.myID=1