Convert SUM of integer to HH:MM format - sql

I have time stored in minutes in integer datatype which has to be displayed in HH:MM format. For example: if total minutes is 80 then it should convert to 01:20.
select SUM(OTTime) from dbo.TableOT where ....
I have tried some queries but didn't get the exact output.
Updated Query:
SELECT SUM(t.OTTime),d.combovalue
FROM dbo.employee e
join dbo.OT t
on e.id = t.employeeid
JOIN dbo.combovalues d
ON e.department = d.id
GROUP By d.combovalue

Try this Single Query:
DECLARE #Duration int
SET #Duration= 4000
SELECT CAST( CAST((#Duration) AS int) / 60 AS varchar) + ':' + right('0' + CAST(CAST((#Duration) AS int) % 60 AS varchar(2)),2)
For Updated Query:
SELECT d.combovalue,CAST(CAST((SUM(t.OTTime)) AS int) / 60 AS varchar) + ':'
+ right('0' + CAST(CAST((SUM(t.OTTime)) AS int) % 60 AS varchar(2)),2)
FROM dbo.employee e join dbo.OT t on e.id = t.employeeid
JOIN dbo.combovalues d ON e.department = d.id
GROUP By d.combovalue

Instead of #minutes variable you can use SUM(OTTime) and a from clause in this below Query
DECLARE #minutes INT=80
SELECT CASE WHEN #minutes >= 60 THEN (SELECT CAST((#minutes / 60) AS VARCHAR(2)) + ':' + CASE WHEN (#minutes % 60) > 0 THEN CAST((#minutes % 60) AS VARCHAR(2))
ELSE '' END)
ELSE CAST((#minutes % 60) AS VARCHAR(2)) END
For Eg:
SELECT CASE WHEN SUM(OTTime) >= 60 THEN (SELECT CAST((SUM(OTTime) / 60) AS VARCHAR(2)) + ':' + CASE WHEN (SUM(OTTime) % 60) > 0 THEN CAST((SUM(OTTime) % 60) AS VARCHAR(2))
ELSE '' END)
ELSE CAST((SUM(OTTime) % 60) AS VARCHAR(2)) END
from dbo.TableOT where ....
Create a SCALAR Function and pass the
select dbo.Minutes_to_HrsMts (SUM(OTTime)) from dbo.TableOT where ....
Function:
CREATE Function dbo.Minutes_to_HrsMts (#minutes INT)
RETURNS nvarchar(30)
AS
BEGIN
declare #hours nvarchar(20)
SET #hours =
CASE WHEN #minutes >= 60 THEN
(SELECT CAST((#minutes / 60) AS VARCHAR(2)) + ':' +
CASE WHEN (#minutes % 60) > 0 THEN
CAST((#minutes % 60) AS VARCHAR(2))
ELSE
''
END)
ELSE
CAST((#minutes % 60) AS VARCHAR(2))
END
return #hours
END

First, I recommend using decimal hours. Much simpler:
SELECT d.combovalue, SUM(t.OTTime) / 60.0
FROM dbo.employee e JOIN
dbo.OT t
ON e.id = t.employeeid JOIN
dbo.combovalues d
ON e.department = d.id
GROUP By d.combovalue;
But that is not your question. If you knew that there are never more than 24 hours, you could use the TIME data type:
CONVERT(VARCHAR(5), DATEADD(minute, SUM(t.OTTime), 0), 8)
If that is too dangerous, then you need to convert to a string:
CONCAT(FORMAT(SUM(t.OTTime) / 60, '00'), ':', FORMAT(SUM(t.OTTime) % 60, '00'))

Related

Operand data type varchar is invalid for avg operator

I keep getting the above error message
"Operand data type varchar is invalid for avg operator"
Can anyone fix it for me? PLEASE
WITH Average -- Calculating Mean
AS (
SELECT avg(convert(VARCHAR(5), DateDiff(s, [ARRIVAL_DATE_TIME], [COMPLETE_DATE_TIME]) / 3600) + ':' + convert(VARCHAR(5), DateDiff(s, [ARRIVAL_DATE_TIME], [COMPLETE_DATE_TIME]) % 3600 / 60) + ':' + convert(VARCHAR(5), (DateDiff(s, [ARRIVAL_DATE_TIME], [COMPLETE_DATE_TIME]) % 60))) AS Average
FROM [CLERKS]
WHERE [ARRIVAL_DATE_TIME] >= DATEADD(dd, - 30, getdate() - 1)
)
,data
AS (
SELECT cast(ARRIVAL_DATE_TIME AS DATE) AS Attendance_Date
,avg(convert(VARCHAR(5), DateDiff(s, [ARRIVAL_DATE_TIME], [COMPLETE_DATE_TIME]) / 3600) + ':' + convert(VARCHAR(5), DateDiff(s, [ARRIVAL_DATE_TIME], [COMPLETE_DATE_TIME]) % 3600 / 60) + ':' + convert(VARCHAR(5), (DateDiff(s, [ARRIVAL_DATE_TIME], [COMPLETE_DATE_TIME]) % 60))) AS Arr_Com
FROM [Clerks]
WHERE [ARRIVAL_DATE_TIME] >= DATEADD(dd, - 30, getdate() - 1)
GROUP BY cast(ARRIVAL_DATE_TIME AS DATE)
)
SELECT a.Attendance_Date
,a.Arr_Com
,c.Average
,abs(a.Arr_Com - b.Arr_Com) AS MR
FROM data a
LEFT JOIN data b ON cast(a.Attendance_Date AS DATETIME) = cast(b.Attendance_Date AS DATETIME) + 1
CROSS JOIN Average c
ORDER BY a.Attendance_Date
GO
Thanks in Advance
Actually, the problem is that the implementation is incorrect. You don't want to average timestamps (5h:3m:20s), but durations.
Hence, you need to calculate the duration in the smallest denominator, in your case seconds, calculate the average in seconds, by using the AVG() function and then formatting that result to look like hh:mm:ss.
Your code should look like:
;WITH Average -- Calculating Mean
AS (
SELECT AVG(DateDiff(s, [ARRIVAL_DATE_TIME], [COMPLETE_DATE_TIME])) as Average
FROM [CLERKS]
WHERE [ARRIVAL_DATE_TIME] >= DATEADD(dd, - 30, getdate() - 1)
)
,data
AS (
SELECT cast(ARRIVAL_DATE_TIME AS DATE) AS Attendance_Date
, AVG(DateDiff(s, [ARRIVAL_DATE_TIME], [COMPLETE_DATE_TIME])) as Arr_Com
FROM [Clerks]
WHERE [ARRIVAL_DATE_TIME] >= DATEADD(dd, - 30, getdate() - 1)
GROUP BY cast(ARRIVAL_DATE_TIME AS DATE)
)
SELECT
Attendance_Date
, Arr_Com
, Average
, avg(convert(VARCHAR(5), MR / 3600) + ':' + convert(VARCHAR(5), MR % 3600 / 60) + ':' + convert(VARCHAR(5), MR % 60))) AS MR
FROM (
SELECT a.Attendance_Date
,a.Arr_Com
,c.Average
, abs(a.Arr_Com - b.Arr_Com) AS MR
FROM data a
LEFT JOIN data b ON cast(a.Attendance_Date AS DATETIME) = cast(b.Attendance_Date AS DATETIME) + 1
CROSS JOIN Average c
) tmp
ORDER BY Attendance_Date

Multiply TIME in SQL Server

I have this query below, basically I'm trying to subtract 2 dates and get the hours.
However, I need the subtracted time to be multiplied by the number of cleaners
SELECT
CONVERT(TIME, ClientBooking.TimeEnd - ClientBooking.TimeStart) AS HoursWorked2,
ClientBooking.NumberOfCleaners AS NumberOfCleaners,
ClientBooking.TimeStart,
ClientBooking.TimeEnd,
ClientBooking.ClientID,
((((ClientInfo.FirstName + N' ') +
ClientInfo.LastName) + N' ') +
ClientInfo.Company) AS ClientName,
((((ClientInfo.Address + N' - ') +
ClientInfo.City) + N' - ') +
ClientInfo.ZipCode) AS Address,
((ClientInfo.PhoneNumber + N' ') +
ClientInfo.EmailAddress) AS Contact,
(ClientBooking.HourlyRate / 60) AS MinRate,
(DATEDIFF(MINUTE,ClientBooking.TimeStart,ClientBooking.TimeEnd) * ClientBooking.NumberOfCleaners) AS Quantity,
ClientBooking.HourlyRate,
DATEDIFF(HOUR, ClientBooking.TimeStart, ClientBooking.TimeEnd) AS HoursWorked
FROM
(dbo.ClientBooking ClientBooking
INNER JOIN
dbo.ClientInfo ClientInfo ON (ClientInfo.ClientID = ClientBooking.ClientID))
Basically, I need to multiply the result of this:
CONVERT(TIME,"ClientBooking"."TimeEnd" - "ClientBooking"."TimeStart" )
How About using this:
Select
convert(time,DATEADD(MINUTE, ( convert(float,(DATEDIFF(minute, ClientBooking.TimeStart, ClientBooking.TimeEnd) * ClientBooking.NumberOfCleaners))/60), ''))
FROM
(dbo.ClientBooking ClientBooking
INNER JOIN
dbo.ClientInfo ClientInfo ON (ClientInfo.ClientID = ClientBooking.ClientID))
Sorry if i have missed a parenthesis !!
You can use DATEDIFF() function..
Something like:
DATEDIFF(hour, ClientBooking.TimeStart, ClientBooking.TimeEnd) * ClientBooking.NumberOfCleaners
as your desired column!
If I understand you correctly this could help you:
declare #start datetime = '2018-11-02 07:00:00'
declare #end datetime = '2018-11-02 08:03:00'
declare #diff int
Select #diff = DATEDIFF(minute,#start,#end)
Select case
when #diff < 60 then concat('00:', right('0' + convert(varchar,#diff), 2))
when #diff >= 60 and #diff < 120 then '01:' + right('0' + convert(varchar,#diff - 60), 2)
when #diff >= 120 and #diff < 180 then '02:' + right('0' + convert(varchar,#diff - 120), 2)
when #diff >= 180 and #diff < 240 then '03:' + right('0' + convert(varchar,#diff - 180), 2)
end
Of course you would need to add the following hours as well.
I've splitted everything up, so it is easier to understand. But you should be able to write it in one line and without variables as well
Hope this helps.

SUM of elapsed time gathered from multiple rows

I am trying to show my team's productivity vs non-productivity percentages based of what type of work they perform throughout the day. I can successfully achieve the format i am looking for with the below code but if an associate is productive in 2 separate departments in 1 day the sub-query fails because it returns multiple rows.
This is what im working with now
DECLARE
#Offset INT ,
#Start DATETIME ,
#Loc INT ,
#NON time(0) ,
#PROD time(0) ,
#TOTAL TIME(0)
SET #Offset = 4
SET #Start = dateadd(day, datediff(day, 0, getdate()), -#Offset)
--SUM OF ALL DEPT CATEGORIES WORKED FOR SELECTED DATE RANGE
select Codes = (DeptCode + ' ' + Opcode)
, TimeSum = right(convert(varchar(9),(sum(datediff(second,StartTime,FinishTime)) / 3600 )),3) + ':' + right('0' + convert(varchar(2),(sum(datediff(second,StartTime,FinishTime)) / 60) % 60 ),2)
, Units = sum(units)
FROM TimeLogNEW
where EventDate = #Start and Location = 10 and ID = 2372013
group by EventDate, id, DeptCode, OpCode
--SUM OF NON PRODUCTIVE HOURS WORKED (HAVING A UNITS SUM OF '0' IS CONSIDERED NON PRODUCTIVE) --NOT INCLUDING 'LL' (WHICH IS A LUNCH PERIOD)
set #NON =
(select NonProd = right(convert(varchar(9),(sum(datediff(second,'0:00:00',TimeSum)) / 3600 )),3) + ':' + right('0' + convert(varchar(2),(sum(datediff(second,'0:00:00',TimeSum)) / 60) % 60 ),2)
from (select
TimeSum = right(convert(varchar(9),(sum(datediff(second,m.StartTime,m.FinishTime)) / 3600 )),3) + ':' + right('0' + convert(varchar(2),(sum(datediff(second,m.StartTime,m.FinishTime)) / 60) % 60 ),2)
,Units = sum(m.units)
FROM TimeLogNEW m
where m.EventDate = #Start and opCode Not in ('ll') and m.Location = 10 and m.ID = 2372013
group by m.EventDate, m.id, m.DeptCode, m.OpCode
)t Group By Units Having Units = 0)
select #NON as 'NON-PROD_Hours'
--SUM OF PRODUCTIVE HOURS WORKED (HAVING A UNITS SUM OF MORE THAN '0' IS CONSIDERED PRODUCTIVE) --NOT INCLUDING 'LL' (WHICH IS A LUNCH PERIOD)
set #PROD =
(select TotalProd = right(convert(varchar(9),(sum(datediff(second,'0:00:00',TimeSum)) / 3600 )),3) + ':' + right('0' + convert(varchar(2),(sum(datediff(second,'0:00:00',TimeSum)) / 60) % 60 ),2)
from (select
TimeSum = right(convert(varchar(9),(sum(datediff(second,m.StartTime,m.FinishTime)) / 3600 )),3) + ':' + right('0' + convert(varchar(2),(sum(datediff(second,m.StartTime,m.FinishTime)) / 60) % 60 ),2)
,Units = sum(m.units)
FROM TimeLogNEW m
where m.EventDate = #Start and opCode Not in ('ll') and m.Location = 10 and m.ID = 2372013
group by m.EventDate, m.id, m.DeptCode, m.OpCode
)t Group By Units Having Units >0 )
select #PROD as 'PROD_Hours'
--SUM OF ALL HOURS WORKED --NOT INCLUDING 'LL' (WHICH IS A LUNCH PERIOD)
set #TOTAL =
(select
TotalTime_NoLunch = right(convert(varchar(9),(sum(datediff(second,StartTime,FinishTime)) / 3600 )),3) + ':' + right('0' + convert(varchar(2),(sum(datediff(second,StartTime,FinishTime)) / 60) % 60 ),2)
FROM TimeLogNEW
where EventDate = #Start and ID = 2372013 and OpCode not in ('ll'))
select #TOTAL as 'SUM_Hours'
--PERCENTAGE OF PRODUCTIVITY
select
[Prod%] =convert(varchar(30),(100 *datediff(minute,'0:00:00',#PROD)/datediff(minute,'0:00:00',#TOTAL) )) +'%'
--PERCENTAGE OF NON-PRODUCTIVITY
select
[NON Prod%] =convert(varchar(30),(100 *datediff(minute,'0:00:00',#NON)/datediff(minute,'0:00:00',#TOTAL) )) +'%'
Result shown. For 7-2-18
If more than 1 of the dept categories codes has greater than 0 Units the sub-query fails. I have been trying to re-arrange the query to allow the grouping of sums equaling 0 and sums having greater than 0, but am stumped here. I am not getting correct results when ungrouping the Units column in the sub.
Here is what the raw data looks like with more than 1 productive operation. 7-3-18
The problem is that you group by DeptCode and OpCode but do not sum these results over the groups. Try this:
DECLARE
#Offset INT ,
#Start DATETIME ,
#Loc INT = 10 ,
#NON INT ,
#PROD INT ,
#TOTAL INT
SET #Offset = 4;
SET #Start = DATEADD(day, DATEDIFF(day, 0, GETDATE()), -#Offset);
--SUM OF ALL DEPT CATEGORIES WORKED FOR SELECTED DATE RANGE
WITH
TimeLog (EventDate, [Location], ID, DeptCode, OpCode, Units, Seconds) AS (
SELECT EventDate, [Location], ID, DeptCode, OpCode, SUM(Units)
, SUM(DATEDIFF(second, StartTime, FinishTime))
FROM TimeLogNEW
GROUP BY EventDate, [Location], ID, DeptCode, OpCode
)
SELECT
Codes = (DeptCode + ' ' + Opcode)
, TimeSum = CAST(DATEADD(second, Seconds, 0) AS time(0))
, Units
FROM TimeLog
WHERE EventDate = #Start AND [Location] = #Loc AND ID = 2372013;
WITH
TimeLog (EventDate, [Location], ID, DeptCode, OpCode, Units, Seconds) AS (
SELECT EventDate, [Location], ID, DeptCode, OpCode, SUM(Units)
, SUM(DATEDIFF(second, StartTime, FinishTime))
FROM TimeLogNEW
GROUP BY EventDate, [Location], ID, DeptCode, OpCode
),
TimeSplit (EventDate, Loc, ID, DC, OC, Units, Seconds, NON_PROD, PROD) AS (
SELECT EventDate, [Location], ID, DeptCode, OpCode, Units, Seconds
, CASE WHEN Units = 0 THEN Seconds ELSE 0 END
, CASE WHEN Units > 0 THEN Seconds ELSE 0 END
FROM TimeLog
)
SELECT #NON = SUM(NON_PROD), #PROD = SUM(PROD), #TOTAL = SUM(Seconds)
FROM TimeSplit
WHERE EventDate = #Start AND Loc = #Loc AND ID = 2372013 AND OC NOT IN ('LL');
-- RESULTS
SELECT
CONVERT(nvarchar(30), #NON/3600) + RIGHT(CONVERT(nvarchar(8), DATEADD(second, #NON, 0), 108), 6) AS 'NON-PROD_Hours',
CONVERT(nvarchar(30), #PROD/3600) + RIGHT(CONVERT(nvarchar(8), DATEADD(second, #PROD, 0), 108), 6) AS 'PROD_Hours',
CONVERT(nvarchar(30), #TOTAL/3600) + RIGHT(CONVERT(nvarchar(8), DATEADD(second, #TOTAL, 0), 108), 6) AS 'SUM_Hours',
CAST(100.0 * #PROD / #TOTAL AS varchar(30)) +'%' AS 'Prod%',
CAST(100.0 * #NON / #TOTAL AS varchar(30)) +'%' AS 'NON Prod%';

Showing only hours and minutes?

How to display only hours and minutes in a field if I get them separately
[SELECT
D.numOperador,
SUM(DATEDIFF(MINUTE, D.FechaSalida, D.FechaLlegada)) / 60 AS \[Horas\] ,
SUM(DATEDIFF(MINUTE, D.FechaSalida, D.FechaLlegada)) % 60 AS \[Minutos\]
FROM
trkOperadores O
INNER JOIN trfDespacho D ON O.NumOperador = D.numOperador
WHERE
O.cveTipoOperador = 2
AND O.NumOperador = 900200
AND D.FechaSalida>='2017-03-10 00:00:00.000' AND D.FechaLlegada<='2017-03-11 00:00:00.000'
GROUP BY
D.NumOperador;
GO]
Time
If you just want to join hrs and mns together in the result, concatenate both of them :
SELECT
D.numOperador,
( cast ( SUM(DATEDIFF(MINUTE, D.FechaSalida, D.FechaLlegada)) / 60 as varchar)
+
cast ( SUM(DATEDIFF(MINUTE, D.FechaSalida, D.FechaLlegada)) % 60 AS varchar ) ) as time
FROM
trkOperadores O
INNER JOIN trfDespacho D ON O.NumOperador = D.numOperador
WHERE
O.cveTipoOperador = 2
AND O.NumOperador = 900200
AND D.FechaSalida>='2017-03-10 00:00:00.000' AND D.FechaLlegada<='2017-03-11 00:00:00.000'
GROUP BY
D.NumOperador;
GO]
I assume that you want something like this.
DECLARE #D1 DATETIME = '20170401'
DECLARE #D2 DATETIME = '20170402 00:05:00'
SELECT RIGHT( '00' + CAST(DATEDIFF(MINUTE, #D1, #D2) /60 AS VARCHAR(2)) , 2) + ':' + RIGHT( '00' + CAST(DATEDIFF(MINUTE, #D1, #D2) % 60 AS VARCHAR(2)) , 2)
-- 24:05
SELECT
D.numOperador,
SUM(DATEDIFF(MINUTE, D.FechaSalida, D.FechaLlegada)) / 60 AS [Horas] ,
SUM(DATEDIFF(MINUTE, D.FechaSalida, D.FechaLlegada)) % 60 AS [Minutos]
CONVERT(VARCHAR(10),CAST(CAST (D.FechaSalida AS FLOAT) - CAST (D.FechaLlegada AS FLOAT) / 86400. AS DATETIME),108) --86400 equal 1 day
FROM
trkOperadores O INNER JOIN trfDespacho D
ON O.NumOperador = D.numOperador
WHERE
O.cveTipoOperador = 2
AND O.NumOperador = 900200
AND D.FechaSalida>='2017-03-10 00:00:00.000' AND D.FechaLlegada<='2017-03-11 00:00:00.000'
GROUP BY
D.NumOperador;
GO

if minute is less than 60 then remove hour part from result

I have a function like this:
ALTER FUNCTION [dbo].[testfunctionstacknew] (#dec NUMERIC(18, 2)) RETURNS Varchar(50)
AS
BEGIN
DECLARE
#hour decimal(18,2),
#Mns decimal(18,2),
#second decimal(18,3)
DECLARE #Average Varchar(50)
select #hour=CONVERT(int,#dec/60/60)
SELECT #Mns = convert(int, (#dec / 60) - (#hour * 60 ));
select #second=#dec % 60;
SELECT #Average =
convert(varchar(9), convert(int, #hour)) + ':' +
-- right('00' + convert(decimal(10,0), convert(decimal(18,2), #hour)), 2) + ':' +
right('00' + convert(decimal(10,0), convert(decimal(18,2), #Mns)), 2) + ':' +
right('00' + CONVERT(decimal(10,0), convert(varchar(10), #second)), 6)
RETURN #Average
END
and i have a stored procedure like this:
select dbo.testfunctionstacknew(
convert(decimal(10,1),
avg(convert(numeric(18,2), datediff(ss, t.dtime, t.PAICdate ))))
) as Avgparkingtime from (select top 10 * from transaction_tbl where locid=6 and dtime >= getdate()-1 order by transactID desc ) t
while executing stored procedure if the average time is less than 60 minutes i am getting result like this:
Avgparkingtime :
0:25:33
if the average time is less than 60 minutes then i dont want to get zero in front of minutes,,(this time only need to show minutes and seconds)..only hour need to show if the minutes is greater than 60 minutes...how i can do this? what changes i have to make in my function ?? any help is very appreciable..
Try changing the part where you build the formatted string like this:
SELECT #Average =
case
when convert(int, #hour) <> 0 then convert(varchar(9), convert(int, #hour)) + ':'
else ''
end +
right('00' + convert(decimal(10,0), convert(decimal(18,2), #Mns)), 2) + ':' +
right('00' + CONVERT(decimal(10,0), convert(varchar(10), #second)), 6)