Issue while calculating SLA in SQL - sql

I am using below function to calculate the elapsed time between 2 input timestamps. Only time spent during business hours should be calculated. Business hrs are Mon-Sat 8 am to 6 pm.
Function call syntax:
select xxxxx('2018.09.28 19:02:28','2018-09-29 10:40:35') Function is giving output as 98 mins, the correct answer is 160 mins.
Function structure is:
Create FUNCTION xxxxx (#LeadAssignTime DATETIME, #LeadContactTime DATETIME)
RETURNS VARCHAR(9)
AS
BEGIN
DECLARE #Temp BIGINT
SET #Temp=0
DECLARE #LeadAssignDay VARCHAR(9)
SET #LeadAssignDay = CONVERT(VARCHAR(9),#LeadAssignTime, 112)
DECLARE #LeadContactDay VARCHAR(9)
SET #LeadContactDay = CONVERT(VARCHAR(9),#LeadContactTime, 112)
DECLARE #StartTime VARCHAR(9)
SET #StartTime = CONVERT(VARCHAR(9),#LeadAssignTime, 108)
DECLARE #FinishTime VARCHAR(9)
SET #FinishTime = CONVERT(VARCHAR(9),#LeadContactTime, 108)
DECLARE #WorkStart VARCHAR(9)
SET #WorkStart = '08:00:00'
DECLARE #WorkFinish VARCHAR(9)
SET #WorkFinish = '18:00:00'
IF (#StartTime<#WorkStart)
BEGIN
SET #StartTime = #WorkStart
END
IF (#FinishTime>#WorkFinish)
BEGIN
SET #FinishTime=#WorkFinish
END
DECLARE #CurrentDate VARCHAR(9)
SET #CurrentDate = CONVERT(VARCHAR(9),#LeadAssignTime, 112)
DECLARE #LastDate VARCHAR(9)
SET #LastDate = CONVERT(VARCHAR(9),#LeadContactTime, 112)
WHILE(#CurrentDate<=#LastDate)
BEGIN
IF (DATEPART(dw, #CurrentDate)!=1 )
BEGIN
IF (#CurrentDate!=#LeadAssignDay) AND (#CurrentDate!=#LeadContactDay)
BEGIN
SET #Temp = (#Temp + (8*60))
END
ELSE IF (#CurrentDate=#LeadAssignDay) AND (#CurrentDate!=#LeadContactDay)
BEGIN
SET #Temp = #Temp + DATEDIFF(MINUTE, #StartTime, #WorkFinish)
END
ELSE IF (#CurrentDate!=#LeadAssignDay) AND (#CurrentDate=#LeadContactDay)
BEGIN
SET #Temp = #Temp + DATEDIFF(MINUTE, #WorkStart, #FinishTime)
END
ELSE IF (#CurrentDate=#LeadAssignDay) AND (#CurrentDate=#LeadContactDay)
BEGIN
SET #Temp = DATEDIFF(MINUTE, #StartTime, #FinishTime)
END
END
SET #CurrentDate = CONVERT(VARCHAR(9),DATEADD(day, 1, #CurrentDate),112)
END
Return #TEMP
END

You're going around your loop twice, but in the first iteration, you fall into the second IF block and setting #temp to be -62
In the second iteration, you fall into the third IF block and calculate 160 for the difference between #WorkStart and #FinishTime, but then this is added to the value already in #Temp. 160-62 = 98.
You'll need your second IF block to check if 'start time' is before 'work finish' before executing that logic.
(#CurrentDate=#LeadAssignDay) AND (#CurrentDate!=#LeadContactDay)
needs to become
(#CurrentDate=#LeadAssignDay) AND (#CurrentDate!=#LeadContactDay) AND ( #StartTime < #WorkFinish)
I haven't done any vetting beyond the one use case. Make sure to do some thorough testing.

Related

Convert 'mm:ss' in to time in SQL Server

I have a string which contains a duration in minutes and seconds, as '1302:47'.
I want to store this in SQL Server and I chose the time data type.
How do I convert '1302:47' in to hrs:mins:secs to a time datatype?
I tried
SELECT TRY_PARSE('1302:40' AS time)
SELECT TRY_CONVERT(time, '1302:40')
and end up with NULL both times implying the conversion failed.
I am expecting 21:7:40 as in 21hrs, 7mins and 40seconds.
Should I use a different data type?
Should I convert it all to seconds and just store as an int?
You need to split your string by ':' char, since that time in invalid. That's why you're getting a NULL value.
After that, you can try parse both the minutes and the seconds.
Finally, just add the minutes and seconds into a new empty time.
Example supporting the max of 23h:
DECLARE #date VARCHAR(20) = '1302:40';
DECLARE #min INT = ISNULL(TRY_PARSE(LEFT(#date,CHARINDEX(':',#date)-1) AS INT), 0);
DECLARE #sec INT = ISNULL(TRY_PARSE(RIGHT(#date,LEN(#date)-CHARINDEX(':',#date)) AS INT), 0);
DECLARE #time TIME = '00:00'
PRINT DATEADD(s, #sec, DATEADD(mi, #min, #time));
-- Outputs: 21:42:40.0000000
Example supporting more than 23h:
DECLARE #date VARCHAR(20) = '1302:47';
--DECLARE #date VARCHAR(20) = '3600:60';
DECLARE #min INT = ISNULL(TRY_PARSE(LEFT(#date,CHARINDEX(':',#date)-1) AS INT), 0);
DECLARE #sec INT = ISNULL(TRY_PARSE(RIGHT(#date,LEN(#date)-CHARINDEX(':',#date)) AS INT), 0);
DECLARE #time TIME = '0001-1-1 00:00'
IF #min < 1440
BEGIN
PRINT CAST(DATEADD(s, #sec, DATEADD(mi, #min, #time)) AS VARCHAR(8));
END
ELSE
BEGIN
IF #sec = 60
BEGIN
SET #sec = 0;
SET #min = #min +1;
END
PRINT CONCAT(#min/60, ':', FORMAT(#min - (#min/60) * 60,'0#'), ':', FORMAT(#sec,'0#'))
END
-- Scenario #1. Given '1302:47', outputs: 21:42:47
-- Scenario #2. Given '3600:60', outputs: 60:01:00

SQL SERVER - Need a Simple T-SQL Program to iterate date

My procedure that I am calling works on day by day basis. I need to pass/iterate by one day upto the current date to the procedure for it to perform the action. Can some help with that. Here is the sample that I tried but it fails to work. I am beginner.
USE [aaa]
GO
DECLARE #return_value int
DECLARE #VarDate1 Datetime ='2015-09-30'
DECLARE #VarDate2 Datetime ='2015-09-30'
WHILE (#VarDate2 <= '2015-12-10')
BEGIN
EXEC #return_value = [dbo].[procname]
#tday1 = #VarDate1 ,
#tday2 = #VarDate2
SET #VarDate2 = DATEADD(DAY, 1, #VarDate2)
set #VarDate1 = #VarDate2
SELECT 'Return Value' = #return_value
END
GO
By checking your code, you're probably getting an error while trying to set the value for #VarDate1 and #VarDate2. Try the code below:
DECLARE #return_value int
DECLARE #VarDate1 Datetime = CAST('20150930 00:00:00' AS DATETIME)
DECLARE #VarDate2 Datetime = CAST('20150930 00:00:00' AS DATETIME)
WHILE (#VarDate2 <= '20151210') BEGIN
SET #VarDate2 = DATEADD(DAY, 1, #VarDate2)
SET #VarDate1 = #VarDate2
PRINT #VarDate2 --Change your logic here
END
GO

How to compare time in 24 hours format in sql server

I want to compare two time values with current time in sql server. The time is in 24 hours format. The code I am trying is,
declare #StartTime varchar(10)='16:30'
declare #EndTime varchar(10)='10:10'
declare #CurrTime varchar(10)='09:30'
select case when CONVERT(time,#CurrTime) between CONVERT(time,#StartTime) and CONVERT(time,#EndTime) then 'SUCCESS' else 'FAIL' end
and gives the output as 'FAIL'.
Please suggest solution.
You need to use datetime datatype and CASE WHEN to check if start date > end date to apply DATEADD to star date in case it is bigger then end date:
DECLARE #Start nvarchar(5)= N'16:30',
#End nvarchar(5)= N'10:10',
#Curr nvarchar(5)=N'09:30'
DECLARE #curdate nvarchar(9) = CONVERT(nvarchar(10),GETDATE(),112)+' '
DECLARE #starttime datetime = #curdate + #Start + ':00.000',
#endtime datetime = #curdate + #End + ':00.000',
#currtime datetime = #curdate + #Curr + ':00.000'
SELECT CASE WHEN #currtime between (
CASE WHEN #starttime > #endtime
THEN DATEADD(day,-1,#starttime)
ELSE #starttime END
) and #endtime THEN 'SUCCESS'
ELSE 'FAIL' END as result

Data operations

I wrote a stored procedure who take a reference date, and add a hour to this element.
Here is my line doing the operation :
DATEADD(day, DATEDIFF(DAY, 0, #conductor_date), [HOUR])
For example, whith #conductor_date = '2015-10-15' and [HOUR] = 23:00 it works and generate me a date like that : '2015-10-15:23:00:00'
I face a logical issue when the value [HOUR] is more than 24. In fact, to solve my problem I need to generate '2015-10-16:00:40:00' when [HOUR] = 24:40
Actualy with this values, I face the logical following exception :
The conversion of a varchar data type to a datetime data type resulted
in an out-of-range value.
To sum up, I need to take care of hours that are more than '23:59' and switch to the next day :
DECLARE #conductor_date datetime
DECLARE #hour varchar(5)
SET #conductor_date = '2015-10-15'
SET #hour = '24:40'
SELECT DATEADD(day, DATEDIFF(DAY, 0, #conductor_date), #hour)
Expected : 2015-10-16:00:40:00
According to the documentation, date / time types don't support times larger then 23:59:59.9999999. You have to do manual string parsing for this.
First you need to extract the total hours, divide that by 24 to get total days. Then calculate leftover hours, and with that reconstruct your time offset.
With these in hand, you can build your required output value:
DECLARE #v VARCHAR(20) = '24:40'
DECLARE #start VARCHAR(20) = '2015-10-15'
DECLARE #days INT
DECLARE #leftover INT
SET #leftover = CAST(LEFT(#v, 2) AS INT)
SET #days = #leftover / 24
SET #leftover = #leftover - #days * 24
SET #v = CAST(#leftover AS VARCHAR(2)) + SUBSTRING(#v, 3, 20)
SELECT DATEADD(DAY, #days + DATEDIFF(DAY, 0, #start), #v)
Here's a working SQLFiddle.
This supports time string that start with HH (leading zeros) with any valid accuracy (HH:mm:ss.fffffff).
You can split your #hour field into hours and minutes and add them separately:
DECLARE #conductor_date datetime
DECLARE #hour varchar(5)
DECLARE #hours int
DECLARE #minutes int
DECLARE #offset datetime
SET #conductor_date = '2015-10-15'
SET #hour = '24:40'
SET #hours = cast(left(#hour, 2) as int)
SET #minutes = cast(right(#hour, 2) as int)
SET #offset = dateadd(day, datediff(day, 0,#conductor_date), 0) -- the begin of the day
SELECT DATEADD(hour, #hours, dateadd(minute, #minutes, #offset))
Of course all can be done in one line but for sake of visualization I have put it into separate statements.
You may try below query
SELECT DATEADD(MINUTE,(LEFT(#hour,2)*60+RIGHT(#hour,2)),#conductor_date)

SQL Difference betwen two dates (Segmented by hours)

I have a shift database which tells me the start and end time of a shift for an individual, i.e. 20/8/2014 07:00:00 to 20/08/2014 15:00:00
However, I need to work out how many people were on shift during a particular hour, i.e. 07:00:00 - 10, 08:00:00 12 etc, as we need to reflect on why performance may have dipped etc, is it because we were short staffed etc?
I can do datediff, to see the total number of hours they were on shift, but I would need to put together some sort of tally chart I guess to do the breakdown, i.e.
Shift 07:00-15:00 - Joe Bloggs
06:00 - 0
07:00 - 1
08:00 - 1
09:00 - 1
14:00 - 1
15:00 - 0
I hope this make sense.
Karen
this code set in your SP and pass two parameter as startdate and enddate
CREATE Table #Temp(Datedif varchar(100))
DECLARE #counter int;
select #counter = datediff(hour,'8/20/2013 07:00:00','8/20/2013 15:00:00')
DECLARE #StartHr varchar(50);
SET #StartHr = Substring(Convert(varchar(50),'8/20/2013 07:00:00'),charindex(' ','8/20/2013 07:00:00'),6)
INSERT INTO #Temp(Datedif)VAlues( #StartHr+' - 1')
WHILE #counter > 1
BEGIN
DECLARE #NextHr varchar(50);
SET #NextHr = Substring(#StartHr,1,charindex(':',#StartHr)-1) + 1
IF(#NextHr LIKE '%' + ':' + '%')
BEGIN
INSERT INTO #Temp(Datedif)VAlues( #NextHr+' - 1')
END
ELSE
BEGIN
IF(len(#NextHr) > 1)
BEGIN
INSERT INTO #Temp(Datedif)VAlues( #NextHr+':00 - 1')
END
ELSE
BEGIN
INSERT INTO #Temp(Datedif)VAlues(' 0'+#NextHr+':00 - 1')
END
END
SET #StartHr = #NextHr+':00-1'
SET #counter = #counter - 1;
END
select * from #Temp
DROP TABLE #Temp
If you are using SQL Server, you can use the script something like below, but the similar logic can be applied for other DBMS
DECLARE
#currentDate datetime;
SET #currentDate = GETDATE( );
-- Hoursly count for last X hours
DECLARE
#counter int;
SET #counter = <Hr Diff>;
WHILE #counter > 0
BEGIN
DECLARE
#startTime datetime;
SET #startTime = DATEADD( HOUR , -#counter , #currentDate );
DECLARE
#endTime datetime ;
SET #endTime = DATEADD( HOUR , -(#counter - 1), #currentDate );
-- Fetch count from your table <Business Logic>
select #startTime, #endTime COUNT( <Entity> ) from tableName BETWEEN #startTime AND #endTime;
SET #counter = #counter - 1;
END;