HI guys,
My litle problem goes like this :
I have this columns : PHONE_NR , TIME ( time field ), Meaning the calling telephone number and call duration. I need to group phone nr and sum the minutes. Filds looks like this :
nr time
726028xxx 00:07:07
735560css 00:07:37
726028xxx 00:07:55
SELECT PHONE_NR, SUM(DATEPART(minute, TIME)) FROM [table] GROUP BY PHONE_NR;
As far as I know this should work for both SQL Server DATETIME and the 2008 TIME data-types.
Example:
DECLARE #tbl TABLE
(
phone_nr varchar(10),
call_time TIME
);
INSERT INTO #tbl VALUES ('726028xxx', '00:07:07');
INSERT INTO #tbl VALUES ('735560css', '00:07:37');
INSERT INTO #tbl VALUES ('726028xxx', '00:07:55');
SELECT phone_nr, SUM(DATEPART(minute, call_time)) AS total_call_time FROM #tbl GROUP BY phone_nr;
Results in:
phone_nr | minutes
726028xxx | 14
735560css | 7
EDIT:
This version is identical to the above, except it also takes into account the seconds and hours (e.g. 1hr 7min 07secs = 67.117 minutes) so it's much more accurate.
SELECT
phone_nr,
SUM(CAST(DATEPART(second, call_time) + (DATEPART(minute, call_time) * 60) + (DATEPART(hour, call_time) * 3600) AS decimal) / 60) AS total_call_time
FROM
#tbl
GROUP BY
phone_nr;
Results in the following if the first record was 01:07:07.
phone_nr | minutes
726028xxx | 75.033332
735560css | 7.616666
You can use DATEDIFF to get the total number of minutes that have passed since time "zero"
SELECT
[PHONE_NR],
SUM(DATEDIFF(minute, '00:00:00', [TIME]))
FROM
[YourTable]
GROUP BY
[PHONE_NR]
declare #v1 varchar(50)
declare #v2 varchar(50)
set #v1='03:10'
set #v2='01:50'
--select cast(left(v1,2) as int) + cast(left(v2,2)as int)
select
cast(
cast(left(#v1,2) as int) + cast(left(#v2,2)as int)
+(cast(right(#v1,2) as int) + cast(right(#v2,2) as int))/60 as varchar)
+':'+cast(( cast(right(#v1,2) as int) + cast(right(#v2,2) as int))%60 as varchar)
Related
In my database, I have a table with a column of type Float which represents the total work hours. I have to sum this value over all rows.
I can't use sum function, because 08.03 = 08 hour, 03 minute.
For example:
00.55 + 00.51=> 01.06
but I want
00.55 + 00.51 => 01.46
My query
Declare #TEMP1 table (TotalHours float)
insert into #TEMP1(TotalHours)
select ol.HrWork TotalHours
from OTLog ol
where EmployeeId = 2048
Declare #attCount int
Declare #attSum int
set #attSum = 0;
set #attCount = (select count(*) from #TEMP1)
print #attCount
while (#attCount <> 0)
begin
set #attSum = #attSum + (select Top 1 (LEFT(TotalHours,1)*60)+(RIGHT(TotalHours,2)) TotalHours from #TEMP1);
delete top(1) from #TEMP1;
set #attCount = #attCount - 1;
print #attSum;
end
print #attSum
select *
from OTLog
where EmployeeId = 2048
Any thoughts would be appreciated.
should use proper data type for storing time and not float
You need to break the float time into hour & minute. sum() it and convert back to your float format
select convert(int, total_minute / 60) + (total_minute % 60) / 100.0
from
(
select total_minute = sum(convert(int ,([hour] * 60) + [minute]))
from
(
select hour = floor(TotalHours), minute = convert(int, TotalHours * 100) % 100
from #TEMP1
) d
) d
You can try to use left(col1,2) to get hour number,right(col1,2) get minute number.
then use SUM to get totle hours and minutes in a subquery.
Then use DATEADD to add time value.
CREATE TABLE T(
col1 VARCHAR(10)
);
INSERT INTO T VALUES ('00.55');
INSERT INTO T VALUES ('00.51');
Query 1:
select FORMAT(DATEADD(minute,m,0)+ DATEADD(hour,h,0),'HH:mm:ss')
from (
SELECT SUM(CAST(left(col1,2) AS INT)) h ,SUM(CAST(right(col1,2) AS INT)) m
FROM T
) t1
Results:
| |
|----------|
| 01:46:00 |
Few issues with your problem:
first, float is not good choice for storing time information, look at date, time, datetime, timestamp, datetime2 - choose one of these, it will prevent such problems from occuring plus you have methods in SQL to work with such datatypes.
second - float is just approximation!, decimal stores exact values, you must be aware of that,
third - you need to be careful when dealing with decimal values in SQL Server, see Precision, scale, and Length (Transact-SQL) and this thread: Why is 199.96 - 0 = 200 in SQL?
After all, I can suggest this query to solve your problem:
select id,
sum(hours) + floor(sum(minutes) / 60) hours,
sum(minutes) % 60 minutes
from (
select id,
floor([time]) [hours],
cast([time] * 100 as int) % 100 [minutes]
from tblFloat
) a group by id
See this SQL fiddle, there you can test difference between using float and decimal (see the differences in a queries).
So I have this table that has date columns in int type.
last_run_date | last_run_time
20171116 | 100234
Im trying to convert this two values into a datetime to be used in datediff statement.
this is my statement
SELECT 1
FROM V_Jobs_All_Servers vjas
WHERE JobName='DailyReports_xxxx' and Step_Name='xxxx'
and DATEDIFF(hour, Convert(varchar,STUFF(STUFF(STUFF(STUFF(STUFF(cast(
Convert(varchar(100),vjas.last_run_date) + Convert(varchar(100),vjas.last_run_time) as varchar)
,5,0,'-'),8,0,'-'),11,0,' '),14,0,':'),17,0,':')), Getdate()) <3
This works but only when the last_run_time value is in two digits hour format
101216, but whenever its one digit hour 91316 it fails with the following error,
The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value.
I am on SQL Server 2005
If you're getting this value from msdb.dbo.sysjobsteps, there's a built-in function, msdb.dbo.agent_datetime(), to convert last_run_date and last_run_time to a datetime already:
select job_id,
step_id,
step_name,
msdb.dbo.agent_datetime(nullif(last_run_date,0),nullif(last_run_time,0)) as last_run_datetime
from msdb.dbo.sysjobsteps
It is an undocumented function. However, at least in my version of SQL Server (2012), that function has this definition:
CREATE FUNCTION agent_datetime(#date int, #time int)
RETURNS DATETIME
AS
BEGIN
RETURN
(
CONVERT(DATETIME,
CONVERT(NVARCHAR(4),#date / 10000) + N'-' +
CONVERT(NVARCHAR(2),(#date % 10000)/100) + N'-' +
CONVERT(NVARCHAR(2),#date % 100) + N' ' +
CONVERT(NVARCHAR(2),#time / 10000) + N':' +
CONVERT(NVARCHAR(2),(#time % 10000)/100) + N':' +
CONVERT(NVARCHAR(2),#time % 100),
120)
)
END
You are massively over complicating this, just pad your time value with a leading 0 and convert from there:
declare #t table(last_run_date int, last_run_time int);
insert into #t values(20171116,90234),(20171116,100234);
select last_run_date
,last_run_time
,convert(datetime,cast(last_run_date as nvarchar(8))
+ ' '
+ stuff(stuff(right('0' + cast(last_run_time as nvarchar(6))
,6)
,5,0,':')
,3,0,':')
,112) as DateTimeData
from #t
Output:
+---------------+---------------+-------------------------+
| last_run_date | last_run_time | DateTimeData |
+---------------+---------------+-------------------------+
| 20171116 | 100234 | 2017-11-16 09:02:34.000 |
| 20171116 | 100234 | 2017-11-16 10:02:34.000 |
+---------------+---------------+-------------------------+
Here's an ugly way...
declare #table table (last_run_date int, last_run_time int)
insert into #table
values
(20171116,100234),
(20171116,91316)
select
cast(cast(cast(last_run_date as varchar) as datetime) + ' ' + stuff(stuff(last_run_time,len(last_run_time) - 1,0,':'),len(stuff(last_run_time,len(last_run_time) - 1,0,':')) - 4,0,':') as datetime)
from #table
DECLARE #temp TABLE (last_run_date int, last_run_time int)
INSERT INTO #temp VALUES (20171116, 100234)
SELECT convert(datetime,CAST(last_run_date as varchar))
+ Convert(time, Dateadd(SECOND, Right(last_run_time,2)/1
,Dateadd(MINUTE, Right(last_run_time,4)/100
,Dateadd(hour, Right(last_run_time,6)/10000
,'1900-01-01'
)
)
)
) [DateConverted]
FROM #temp
Produces Output:
DateConverted
2017-11-16 10:02:34.000
You can see how this works by doing each part individually.
SELECT Dateadd(hour, Right(last_run_time,6)/10000
,'1900-01-01')
FROM #temp
Gives the hours position.
SELECT Dateadd(MINUTE, Right(last_run_time,4)/100
,Dateadd(hour, Right(last_run_time,6)/10000
,'1900-01-01'))
FROM #temp
Gives the hours plus minutes position.
Etc.
I try to cast time in HH:MM Format it works fine but when i insert time above 23 hours i.e 24:0 it generates error
"The conversion of a varchar data type to a datetime data type resulted in an out-of-range value. "
Below is code
CREATE TABLE mytable
(
timeduration varchar(25)
)
INSERT INTO mytable VALUES ('05:30')
INSERT INTO mytable values ('24:0')
INSERT INTO mytable values ('04:33')
-- OUTPUT SHOULD BE 34:3 MINUTES
select CAST
(
(SUM (datepart(hh, convert (varchar, timeduration, 108))) +
(sum(datepart(mi, convert (varchar, timeduration, 108)))/60) ) AS VARCHAR(2)
)
+ ':' +
CAST
(
sum(datepart(mi, convert (varchar, timeduration, 108))) - 60 * (sum(datepart(mi, convert (varchar, timeduration, 108)))/60)
as VARCHAR(2))
from mytable
Your problem is '24:00', Here should be '00:00' if you want it to work.
But then you have to add case expressions to you query. I suggest you to rewrite as:
DECLARE #mytable TABLE
(
timeduration VARCHAR(25)
)
INSERT INTO #mytable
VALUES ( '05:30' )
INSERT INTO #mytable
VALUES ( '24:0' )
INSERT INTO #mytable
VALUES ( '04:33' );
WITH cte
AS ( SELECT SUM(CAST(SUBSTRING(timeduration, 1, CHARINDEX(':', timeduration) - 1) AS INT)) AS Hours ,
SUM(CAST(SUBSTRING(timeduration, CHARINDEX(':', timeduration) + 1, 5) AS INT)) AS Minutes
FROM #mytable
)
SELECT CAST(Hours + Minutes / 60 AS NVARCHAR(20)) + ':' + CAST(Minutes % 60 AS NVARCHAR(20)) AS Duration
FROM cte
Output:
Duration
34:3
If I have result set like that :
Work_hour(hh:mm)
10:24
12:59
06:28
where Work_hour is of type varchar
How to sum those hours and minutes with the same format ?
SELECT CAST(FLOOR(TMP1.MINS/60) AS VARCHAR) + ':' + CAST((TMP1.MINS % 60) AS VARCHAR) FROM (
SELECT SUM (CAST(LEFT(time_column, 2) AS INT) * 60 + CAST(RIGHT(time_column, 2) AS INT)) as MINS FROM table1
) AS TMP1
Where time_column is the column in the table and table1 is the name of the table. Example:
create table table1 (
time_column varchar(10)
);
insert into table1 (time_column) values ('12:20'), ('10:40'), ('15:50');
Results in: 38:50
Try this one -
Query:
DECLARE #temp TABLE
(
work_hour CHAR(5)
)
INSERT INTO #temp (work_hour)
VALUES
('10:24'),
('12:59'),
('06:28')
;WITH cte AS
(
SELECT mn = SUM(DATEDIFF(MINUTE, '19000101', CAST('19000101 ' + work_hour AS DATETIME)))
FROM #temp
)
SELECT CAST(FLOOR(mn / 60) AS VARCHAR(5)) + ':' + CAST(mn % 60 AS VARCHAR(2))
FROM cte
Output:
hm
--------
29:51
Update 2:
DECLARE #temp TABLE
(
transtime_out DATETIME
, transtime_in DATETIME
)
INSERT INTO #temp (transtime_out, transtime_in)
VALUES
('2013-05-19 16:40:53.000', '2013-05-19 08:58:07.000'),
('2013-05-19 16:40:53.000', '2013-05-19 08:58:07.000')
SELECT diff = LEFT(CONVERT(VARCHAR(10), CAST(SUM(CAST(a.transtime_out - a.transtime_in AS FLOAT)) AS DATETIME), 108), 5)
FROM #temp a
I have a table in SQL Server
id int,
enters time,
left time,
date datetime,
user varchar(50)
Now I want to get the time difference between enters and lefts but I get this error message:
Msg 8117, Level 16, State 1, Line 1
Operand data type time is invalid for subtract operator.
How can I to get the time has passed?
For example, if user enters at 8.00 and leaves at 9.15 I need to get 1.15.
How can I do this?
declare #MyTable table(enters time, lefttime time)
insert #MyTable values('8:00', '9:05')
select *,
cast(datediff(hour, enters, lefttime) as varchar) + ':' +
right('0' + cast(datediff(minute, enters, lefttime) % 60 as varchar), 2)
from #MyTable
[EDIT]
Added 0 padding to avoid showing 1:5, instead of 1:05.
Another way to do this:
select cast(dateadd(minute, datediff(minute, enters, lefttime), 0) as time)
from #MyTable
The result will be of time type, not varchar.
Look at DATEDIFF function.
DECLARE #enters datetime = CAST('2011-06-26T08:00:00' as datetime);
DECLARE #left datetime = CAST('2011-06-26T09:15:00' as datetime);
SELECT CAST(DATEDIFF(HH, #enters, #left) as varchar(max))
+ ':' + CAST(DATEDIFF(MI, #enters, #left) % 60 as varchar(max))
select
id
,enters
,[left]
,date
,[user]
,CONVERT(time,DATEADD(second, DATEDIFF(second,enters,[left]), 0)) as [Difference]
from
MyTable
Simple method is
convert the DATE to time datatype
convert()
and then use substring to find the
difference based on the position
between substr(date,0,0) and time