Related
I have a column called "WrkHrs" and the data type is time(hh:mm:ss). I want to sum up the working hours for employees. But since it's time data type sql server doesn't let me use like sum(columnname).
How can I sum up the time data type fieled in sql query?
SELECT EmployeeID, minutes_worked = SUM(DATEDIFF(MINUTE, '0:00:00', WrkHrs))
FROM dbo.table
-- WHERE ...
GROUP BY EmployeeID;
You can format it pretty on the front end. Or in T-SQL:
;WITH w(e, mw) AS
(
SELECT EmployeeID, SUM(DATEDIFF(MINUTE, '0:00:00', WrkHrs))
FROM dbo.table
-- WHERE ...
GROUP BY EmployeeID
)
SELECT EmployeeID = e,
WrkHrs = RTRIM(mw/60) + ':' + RIGHT('0' + RTRIM(mw%60),2)
FROM w;
However, you're using the wrong data type. TIME is used to indicate a point in time, not an interval or duration. Wouldn't it make sense to store their work hours in two distinct columns, StartTime and EndTime?
In order to sum up the working hours for an employee you can calculate the difference between the shift start time and end time in minutes and convert it to readable format as following:
DECLARE #StartTime datetime = '08:00'
DECLARE #EndTime datetime = '10:47'
DECLARE #durMinutes int
DECLARE #duration nvarchar(5)
SET #durMinutes = DATEDIFF(MINUTE, #StartTime, #EndTime)
SET #duration =
(SELECT RIGHT('00' + CAST((#durMinutes / 60) AS VARCHAR(2)),2) + ':' +
RIGHT('00' + CAST((#durMinutes % 60) AS VARCHAR(2)), 2))
SELECT #duration
The result : 02:47
two hours and 47 minutes
select DATEDIFF(MINUTE, '0:00:00', '00:02:08')
results in :- 2
select DATEDIFF(SECOND, '0:00:00', '00:02:08')
results in :- 128
Using seconds gives a better answer.
So I think the answer can be
SELECT
EmployeeId
, seconds_worked = SUM (DATEDIFF (SECOND, '0:00:00', WrkHrs))
FROM
tbl_employee
GROUP BY
EmployeeId;
DECLARE #Tab TABLE
(
data CHAR(5)
)
INSERT #Tab
SELECT '25:30' UNION ALL
SELECT '31:45' UNION ALL
SELECT '16:00'
SELECT STUFF(CONVERT(CHAR(8), DATEADD(SECOND, theHours + theMinutes,
'19000101'), 8), 1, 2, CAST((theHours + theMinutes) / 3600 AS VARCHAR(12)))
FROM (
SELECT ABS(SUM(CASE CHARINDEX(':', data) WHEN 0 THEN 0 ELSE 3600 *
LEFT(data, CHARINDEX(':', data) - 1) END)) AS theHours,
ABS(SUM(CASE CHARINDEX(':', data) WHEN 0 THEN 0 ELSE 60 *
SUBSTRING(data, CHARINDEX(':', data) + 1, 2) END)) AS theMinutes
FROM #Tab
) AS d
For MS SQL Server, when your WorkingTime is stored as a time, or a varchar in order to sum it up you should consider that:
1) Time format is not supporting sum, so you need to parse it
2) 23:59:59.9999999 is the maximum value for the time.
So, the code that will work to get you the total number of WorkingHours:WorkingMinutes:WorkingSeconds would be the following:
SELECT
CAST(FORMAT((SUM((DATEPART("ss",WorkingTime) + DATEPART("mi",WorkingTime) * 60 + DATEPART("hh",WorkingTime) * 3600)) / 3600),'00') as varchar(max)) + ':' +
CAST(FORMAT((SUM((DATEPART("ss",WorkingTime) + DATEPART("mi",WorkingTime) * 60 + DATEPART("hh",WorkingTime) * 3600)) % 3600 / 60),'00') as varchar(max)) + ':' +
CAST(FORMAT((SUM((DATEPART("ss",WorkingTime) + DATEPART("mi",WorkingTime) * 60 + DATEPART("hh",WorkingTime) * 3600)) % 3600 % 60),'00') as varchar(max)) as WorkingTimeSum
FROM TableName
It must be as simple as that.
Steps
convert time to seconds
sum the RESULT
convert the sum to time
Eg:
take a case you might want to sum the following time:
| present_hours |
|-----------------|
| 00:01:20.000000 |
|-----------------|
| 00:01:13.000000 |
|-----------------|
| 00:01:45.000000 |
|-----------------|
| 00:01:03.000000 |
|-----------------|
| 00:01:10.000000 |
|-----------------|
| 00:00:56.000000 |
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(present_hours))) as total_present_hours FROM time_booking;
I want to sum all the time differences to show the total hours worked.
select
aaaa
from
employee B
inner join
(select
s.emp_reader_id,
Sum(case when s.in_time is not null and s.out_time is not null and s.shift_type_id=5 and LOWER(DATENAME(dw, [att_date]))='friday'then
cast(datediff(minute,'00:00:00', '23:59:59') / 60 +
(datediff(minute,'00:00:00', '23:59:59') % 60 / 100.0) as decimal(7, 4)
) end) as aaaa
from
Daily_attendance_data s
left outer join
employee bb on s.emp_reader_id = bb.emp_reader_id
where
att_date between '2018-10-01' and '2018-10-31'
and s.emp_reader_id = 1039
group by
s.emp_reader_id) A on B.emp_reader_id = A.emp_reader_id
Current output:
aaaa
47.1800
which gives the list of times by hours but then I want to sum it up to a grand total.
It would just total
Sample data :
23:59
23:59
Expected output:
47.58
I think you should convert all times to seconds, calculate the SUM then convert the total to HH:mm:ss.
Calculate The SUM of seconds
DECLARE #TimeinSecond as integer = 0
select #TimeinSecond = Sum(DATEDIFF(SECOND, '0:00:00', [WorkHrs]))
from Daily_attendance_data
Convert the HH:mm:ss Format
SELECT RIGHT('0' + CAST(#TimeinSecond / 3600 AS VARCHAR),2) + ':' +
RIGHT('0' + CAST((#TimeinSecond / 60) % 60 AS VARCHAR),2) + ':' +
RIGHT('0' + CAST(#TimeinSecond % 60 AS VARCHAR),2)
References
How to convert hh:mm:ss to seconds in SQL Server with more than 24 hours
SQL SERVER – Convert Seconds to Hour : Minute : Seconds Format
If your date type is DateTime.
you can try to let your value split two part.
hours get value need to condider carry from minutes so do SUM(intpart) + SUM(floatpart) / 60
minutes get value from SUM(floatpart) % 60
look like this.
SELECT concat(SUM(intpart) + SUM(floatpart) / 60,':', SUM(floatpart) % 60)
FROM (
SELECT cast(SUBSTRING (cast(col as varchar),0,3) as int) intpart,
cast(SUBSTRING (cast(col as varchar),CHARINDEX(':',col) +1,2)as int) floatpart
FROM T
) t1
sqlfiddle
I have a database column containing an integer value that represents a systems up time in seconds. I'd really like a query to be able to show me that up time in a easy to read format day(s) hour(s) minute(s) but I'm not quite sure how to do it. A lot of examples I've found appear to use parameters as an example but never much of how to use it in a select function.
I need the time to be the same as what's displayed on a website too. I tried one query earlier and its added days and removed minutes. Can anyone help me out?
Source data:
PDT0014 6141
PDT0008 4990
PDT0024 840227
PDT0033 2301
PDT0035 5439
PDT0005 3434
PDT0019 5482
Sample code:
SELECT tblAssets.AssetName,
(case when tblAssets.Uptime> (24*60*60)
then
cast(datepart(day,datediff(dd, 0, dateadd(second, tblAssets.Uptime, 0))) as varchar(4))
+ ' Day(s) ' + convert(varchar(2), dateadd(second, tblAssets.Uptime, 0), 108) +' Hour(s)'
else
convert(varchar(5), dateadd(second, tblAssets.Uptime, 0), 108) + ' Hour(s) Minute(s) '
end) AS Uptime
FROM tblAssets
Desired Query Output:
PDT0014 01:42 Hour(s) Minute(s)
PDT0008 01:23 Hour(s) Minute(s)
PDT0024 10 Day(s) 17 Hour(s)
PDT0033 00:38 Hour(s) Minute(s)
PDT0035 01:30 Hour(s) Minute(s)
PDT0005 00:57 Hour(s) Minute(s)
PDT0019 01:31 Hour(s) Minute(s)
Depending on the output you want:
DECLARE #s INT = 139905;
SELECT CONVERT(VARCHAR(12), #s /60/60/24) + ' Day(s), '
+ CONVERT(VARCHAR(12), #s /60/60 % 24)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), #s /60 % 60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), #s % 60), 2);
Result:
1 Day(s), 14:51:45
Or:
DECLARE #s INT = 139905;
SELECT
CONVERT(VARCHAR(12), #s /60/60/24) + ' Day(s), '
+ CONVERT(VARCHAR(12), #s /60/60 % 24) + ' Hour(s), '
+ CONVERT(VARCHAR(2), #s /60 % 60) + ' Minute(s), '
+ CONVERT(VARCHAR(2), #s % 60) + ' Second(s).';
Result:
1 Day(s), 14 Hour(s), 51 Minute(s), 45 Second(s).
You can replace 60/60/24 with 86400 etc. but I find it better self-documenting if you leave in the /seconds/minutes/hours calculations. And if you are going against a table, just use column_name in place of #s.
I tend to use:
CAST(FLOOR(seconds / 86400) AS VARCHAR(10))+'d ' +
CONVERT(VARCHAR(5), DATEADD(SECOND, Seconds, '19000101'), 8)
The top part just gets your days as an integer, the bottom uses SQL-Server's convert to convert a date into a varchar in the format HH:mm:ss after converting seconds into a date.
e.g.
SELECT Formatted = CAST(FLOOR(seconds / 86400) AS VARCHAR(10))+'d ' +
CONVERT(VARCHAR(5), DATEADD(SECOND, Seconds, '19000101'), 8),
Seconds
FROM ( SELECT TOP 10
Seconds = (ROW_NUMBER() OVER (ORDER BY Object_ID) * 40000)
FROM sys.all_Objects
ORDER BY Object_ID
) S
Example on SQL Fiddle
N.B. Change CONVERT(VARCHAR(5), DATEADD(.. to CONVERT(VARCHAR(8), DATEADD(.. to keep the seconds in the result
EDIT
If you don't want seconds and need to round to the nearest minute rather than truncate you can use:
SELECT Formatted = CAST(FLOOR(ROUND(Seconds / 60.0, 0) * 60 / 86400) AS VARCHAR(10))+'d ' +
CONVERT(VARCHAR(5), DATEADD(SECOND, ROUND(Seconds / 60.0, 0) * 60, '19000101'), 8),
Seconds
FROM ( SELECT Seconds = 3899
) S
I have just replaced each reference to the column seconds with:
ROUND(Seconds / 60.0, 0) * 60
So before doing the conversion rounding your seconds value to the nearest minute
You can convert seconds to days by dividing by 86400
You can convert seconds to hours by dividing by 3600, but you need to get the remainder
(by subtracting off the total days converted to hours)
You can convert seconds to minutes by dividing by 60, but you need to get the remainder (by subtracting off the total hours converted to minutes)
Seconds you can just report, but like minutes you want to only report the remainder of seconds (by sutracting off the total minutes converted to seconds)
SELECT FLOOR( UpTime / 86400 ) AS DAYS
, FLOOR( ( UpTime / 3600 ) - FLOOR( UpTime / 86400 ) * 24 ) AS HOURS
, FLOOR( ( UpTime / 60 ) - FLOOR( UpTime / 3600 ) * 60 ) AS MINUTES
, UpTime - FLOOR( UpTime / 60 ) * 60 AS SECONDS
FROM ( SELECT 269272 AS UpTime ) AS X
269272 represents 3 days (259200 seconds), 2 hours (7200 seconds), 47 minutes (2820 seconds) and 52 seconds.
This query produces:
| DAYS | HOURS | MINUTES | SECONDS |
------------------------------------
| 3 | 2 | 47 | 52 |
Substituting 125 (2 minutes, 5 seconds) for 259200 will produce:
| DAYS | HOURS | MINUTES | SECONDS |
------------------------------------
| 0 | 0 | 2 | 5 |
To convert this to a string representation, you can use SQL Server 2012's FORMAT function:
SELECT CASE
WHEN DAYS > 0 THEN
FORMAT( DAYS, '##' ) + ' Day(s) ' + FORMAT( HOURS, '##' ) + ' Hour(s)'
ELSE
FORMAT( HOURS, '##' ) + ':' + FORMAT( MINUTES, '##' ) + ' Hour(s) Minute(s)'
END AS UpTimeString
FROM (
SELECT FLOOR( UpTime / 86400 ) AS DAYS
, FLOOR( ( UpTime / 3600 ) - FLOOR( UpTime / 86400 ) * 24 ) AS HOURS
, FLOOR( ( UpTime / 60 ) - FLOOR( UpTime / 3600 ) * 60 ) AS MINUTES
, UpTime - FLOOR( UpTime / 60 ) * 60 AS SECONDS
FROM ( SELECT 125 AS UpTime ) AS X
) AS UptimeSubselect
This is another approach using DATEPART():
DECLARE #S INT = 86472,
#START DATETIME = CONVERT(DATETIME,0)
DECLARE #END DATETIME = DATEADD(SECOND,#S, #START)
SELECT CONVERT(VARCHAR(10),DATEPART(DAY,#END)-1) + ' Day(s) ' +
RIGHT(CONVERT(VARCHAR(10),100+DATEPART(HOUR, #END)),2) + ':' +
RIGHT(CONVERT(VARCHAR(10),100+DATEPART(MINUTE, #END)),2) + ':' +
RIGHT(CONVERT(VARCHAR(10),100+DATEPART(SECOND, #END)),2)
If you don't need to format time part:
SELECT CONVERT(VARCHAR(10),DATEPART(DAY,#END)-1) + ' Day(s) ' +
CONVERT(VARCHAR(10),DATEPART(HOUR, #END)) + ' Hour(s)' +
CONVERT(VARCHAR(10),DATEPART(MINUTE, #END)) + ' Minute(s)' +
CONVERT(VARCHAR(10),DATEPART(SECOND, #END)) + ' Second(s)'
DECLARE #Seconds INT = 86200;
SELECT CONVERT(VARCHAR(15),
CAST(CONVERT(VARCHAR(12), #Seconds / 60 / 60 % 24)
+':'+ CONVERT(VARCHAR(2), #Seconds / 60 % 60)
+':'+ CONVERT(VARCHAR(2), #Seconds % 60) AS TIME), 100) AS [HH:MM:SS (AM/PM)]
I have a column called "WrkHrs" and the data type is time(hh:mm:ss). I want to sum up the working hours for employees. But since it's time data type sql server doesn't let me use like sum(columnname).
How can I sum up the time data type fieled in sql query?
SELECT EmployeeID, minutes_worked = SUM(DATEDIFF(MINUTE, '0:00:00', WrkHrs))
FROM dbo.table
-- WHERE ...
GROUP BY EmployeeID;
You can format it pretty on the front end. Or in T-SQL:
;WITH w(e, mw) AS
(
SELECT EmployeeID, SUM(DATEDIFF(MINUTE, '0:00:00', WrkHrs))
FROM dbo.table
-- WHERE ...
GROUP BY EmployeeID
)
SELECT EmployeeID = e,
WrkHrs = RTRIM(mw/60) + ':' + RIGHT('0' + RTRIM(mw%60),2)
FROM w;
However, you're using the wrong data type. TIME is used to indicate a point in time, not an interval or duration. Wouldn't it make sense to store their work hours in two distinct columns, StartTime and EndTime?
In order to sum up the working hours for an employee you can calculate the difference between the shift start time and end time in minutes and convert it to readable format as following:
DECLARE #StartTime datetime = '08:00'
DECLARE #EndTime datetime = '10:47'
DECLARE #durMinutes int
DECLARE #duration nvarchar(5)
SET #durMinutes = DATEDIFF(MINUTE, #StartTime, #EndTime)
SET #duration =
(SELECT RIGHT('00' + CAST((#durMinutes / 60) AS VARCHAR(2)),2) + ':' +
RIGHT('00' + CAST((#durMinutes % 60) AS VARCHAR(2)), 2))
SELECT #duration
The result : 02:47
two hours and 47 minutes
select DATEDIFF(MINUTE, '0:00:00', '00:02:08')
results in :- 2
select DATEDIFF(SECOND, '0:00:00', '00:02:08')
results in :- 128
Using seconds gives a better answer.
So I think the answer can be
SELECT
EmployeeId
, seconds_worked = SUM (DATEDIFF (SECOND, '0:00:00', WrkHrs))
FROM
tbl_employee
GROUP BY
EmployeeId;
DECLARE #Tab TABLE
(
data CHAR(5)
)
INSERT #Tab
SELECT '25:30' UNION ALL
SELECT '31:45' UNION ALL
SELECT '16:00'
SELECT STUFF(CONVERT(CHAR(8), DATEADD(SECOND, theHours + theMinutes,
'19000101'), 8), 1, 2, CAST((theHours + theMinutes) / 3600 AS VARCHAR(12)))
FROM (
SELECT ABS(SUM(CASE CHARINDEX(':', data) WHEN 0 THEN 0 ELSE 3600 *
LEFT(data, CHARINDEX(':', data) - 1) END)) AS theHours,
ABS(SUM(CASE CHARINDEX(':', data) WHEN 0 THEN 0 ELSE 60 *
SUBSTRING(data, CHARINDEX(':', data) + 1, 2) END)) AS theMinutes
FROM #Tab
) AS d
For MS SQL Server, when your WorkingTime is stored as a time, or a varchar in order to sum it up you should consider that:
1) Time format is not supporting sum, so you need to parse it
2) 23:59:59.9999999 is the maximum value for the time.
So, the code that will work to get you the total number of WorkingHours:WorkingMinutes:WorkingSeconds would be the following:
SELECT
CAST(FORMAT((SUM((DATEPART("ss",WorkingTime) + DATEPART("mi",WorkingTime) * 60 + DATEPART("hh",WorkingTime) * 3600)) / 3600),'00') as varchar(max)) + ':' +
CAST(FORMAT((SUM((DATEPART("ss",WorkingTime) + DATEPART("mi",WorkingTime) * 60 + DATEPART("hh",WorkingTime) * 3600)) % 3600 / 60),'00') as varchar(max)) + ':' +
CAST(FORMAT((SUM((DATEPART("ss",WorkingTime) + DATEPART("mi",WorkingTime) * 60 + DATEPART("hh",WorkingTime) * 3600)) % 3600 % 60),'00') as varchar(max)) as WorkingTimeSum
FROM TableName
It must be as simple as that.
Steps
convert time to seconds
sum the RESULT
convert the sum to time
Eg:
take a case you might want to sum the following time:
| present_hours |
|-----------------|
| 00:01:20.000000 |
|-----------------|
| 00:01:13.000000 |
|-----------------|
| 00:01:45.000000 |
|-----------------|
| 00:01:03.000000 |
|-----------------|
| 00:01:10.000000 |
|-----------------|
| 00:00:56.000000 |
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(present_hours))) as total_present_hours FROM time_booking;
Is there a easy way to format a float number in hours in Ms SQL server 2008?
Examples:
1.5 -> 01:30
9.8 -> 09:48
35.25 -> 35:15
Thanks a lot.
I like this question!
DECLARE #input float = 1.5;
DECLARE #hour int = FLOOR(#input);
DECLARE #minutes int = (SELECT (#input - FLOOR(#input)) * 60);
SELECT RIGHT('00' + CONVERT(varchar(2), #hour), 2) + ':' + RIGHT('00' + CONVERT(varchar(2), #minutes), 2);
SELECT SUBSTRING(CONVERT(NVARCHAR, DATEADD(MINUTE, 1.5*60, ''), 108), 1, 5)
This works by:
starting from the "zero" date
adding 1.5 x 60 minutes (i.e. 1.5 hours)
formatting the result as a time, hh:mm:ss (i.e. format "108")
trimming off the seconds part
It is necessary to use 1.5 x 60 minutes instead of 1.5 hours as the DATEADD function truncates the offset to the nearest integer. If you want high-resolution offsets, you can use SECOND instead, suitable scaled (e.g. hours * 60 * 60).
Sure. Easy, but not exactly...straightforward:
declare #hours float
set #hours = -9.8
select substring('- ',2+convert(int,sign(#hours)),1) -- sign
+ right('00' + convert(varchar, floor(abs(#hours))) , 2 ) -- hours component
+ ':' -- delimiter
+ right('00' + convert(varchar,round( 60*(abs(#hours)-floor(abs(#hours))) , 0 ) ) , 2 ) -- minutes
Another option that will give the correct result. You might need to tweak it to round minutes and to ensure that both fields are 2 digits wide.
declare #hours float
set #hours = -9.8
select convert(varchar, datediff(minute,dateadd(minute,#hours*60,convert(datetime,'')),'') / 60 )
+ ':' + convert(varchar, datediff(minute,dateadd(minute,#hours*60,convert(datetime,'')),'') % 60 )
WITH m AS
SELECT Minutes = CAST(#hours * 60 AS int)
)
SELECT CAST(Minutes / 60 AS varchar) + ':' + RIGHT(100 + Minutes % 60, 2)
FROM m
select dateadd(MINUTE, cast((8.18 % 1) * 60 as int), dateadd(hour, cast(8.18 as int), convert(varchar(10), getdate(), 10)))