I am trying to calculate the total hours at the table. However when the total time is more than 24 hour I get wrong result. Lets say total hour is 30 but this query calculates it 6. The other thing is if the total time is less than 24 hours it gives the right result. Can you help me?
SELECT cast(dateadd(SECOND,sum(datediff(SECOND,CAST (s.LOGINHOUR + ':' + s.LOGINMIN + ':' + l.LOGINSEC as time), CAST (s.LOGOUTHOUR + ':' + s.LOGOUTMIN + ':' + s.LOGOUTSEC as time))), '1/1/1900') as time)
from openquery(S, '
SELECT
floor(MOD(logindate,10000)/100) as loginMonth,
MOD(logindate,100) as loginDay,
floor(logintime/10000) as loginHour,
floor(MOD(logintime,10000)/100) as loginMin ,
floor(MOD(logintime,100)) as loginSec,
floor(MOD(logoutdate,10000)/100) as logoutMonth,
MOD(logoutdate,100) as logoutDay,
floor(logouttime/10000) as logoutHour,
floor(MOD(logouttime,10000)/100) as logoutMin,
floor(MOD(logouttime,100)) as logoutSec
FROM lgu00
WHERE (login between date1 AND date2)
AND (logout between date1 AND date2)
')s
I believe I took the following from Adam Machanic's sp_whoisactive stored procedure.
DECLARE @startDate DATETIME2(0) = '2015-01-01';
DECLARE @endDate DATETIME2(0) = '2015-01-02 12:30:01'
SELECT
RIGHT( '0' + CONVERT( VARCHAR(6), DATEDIFF( SECOND, @startDate, @endDate ) / 3600 ), 2 )
+ ':' + RIGHT( '0' + CONVERT( VARCHAR(2), DATEDIFF( SECOND, @startDate, @endDate ) % 3600 / 60 ), 2 ) + ':' + RIGHT( '0' + CONVERT( VARCHAR(2),
DATEDIFF( SECOND, @startDate, @endDate ) % 60 ), 2 ) AS 'hh:mm:ss'
The time
type in sql server only holds up to a maximum of 24 hours. So you need to convert to datetime
and then do a calculation to convert to hours:minutes:seconds.
Also, you need to include your year in your data, otherwise if someone logs in before the year changes and then logs out after, you will get a very large negative difference.
Here is an example... I used a common table expression to calculate the difference in seconds between the two dates, and then it reports on the total difference in the format you need.
;with cte_LogTimes as
(
SELECT
DATEDIFF(second,
CAST(convert(varchar(2),s.LOGINMONTH) + '/'
+ convert(varchar(2),s.LOGINDAY) + '/'
+ convert(varchar(4),s.LOGINYEAR) + ' '
+ convert(varchar(2),s.LOGINHOUR) + ':'
+ convert(varchar(2),s.LOGINMIN) + ':'
+ convert(varchar(2),s.LOGINSEC)
as datetime),
CAST(convert(varchar(2),s.LOGOUTMONTH) + '/'
+ convert(varchar(2),s.LOGOUTDAY) + '/'
+ convert(varchar(4),s.LOGOUTYEAR) + ' '
+ convert(varchar(2),s.LOGOUTHOUR) + ':'
+ convert(varchar(2),s.LOGOUTMIN) + ':'
+ convert(varchar(2),s.LOGOUTSEC)
as datetime)
) seconds
from openquery(S, '
SELECT
floor(@logindate/10000) as loginYear,
floor(MOD(logindate,10000)/100) as loginMonth,
MOD(logindate,100) as loginDay,
floor(logintime/10000) as loginHour,
floor(MOD(logintime,10000)/100) as loginMin ,
floor(MOD(logintime,100)) as loginSec,
floor(logoutdate/10000) as logoutYear,
floor(MOD(logoutdate,10000)/100) as logoutMonth,
MOD(logoutdate,100) as logoutDay,
floor(logouttime/10000) as logoutHour,
floor(MOD(logouttime,10000)/100) as logoutMin,
floor(MOD(logouttime,100)) as logoutSec
FROM lgu00
WHERE (login between date1 AND date2)
AND (logout between date1 AND date2)
')s
)
select convert(varchar(10),SUM(seconds)/3600) + ':'
+ convert(varchar(10),SUM(seconds) % 3600 / 60) + ':'
+ convert(varchar(10),SUM(seconds) % 60)
from cte_LogTimes
Also, if you need your minutes and hours to have leading zeros, this is how I would do that in the final select:
select convert(varchar(10),SUM(seconds)/3600) + ':'
+ replace(str(convert(varchar(10),SUM(seconds) % 3600 / 60),2),' ','0') + ':'
+ replace(str(convert(varchar(10),SUM(seconds) % 60),2),' ','0')
from cte_LogTimes
Assume I have a table likes MyTable: ID | Date_time SELECT A.Total_time/3600 AS 'Hour', (A.Total_time - (A.Total_time/3600)*3600)/60 AS 'Minutes', (A.Total_time - ((A.Total_time/3600)*3600) - ((A.Total_time - (A.Total_time/3600)*3600)/60)*60) AS 'Second' FROM ( SELECT SUM( DATEPART(SECOND, Date_time) + 60*DATEPART(MINUTE, Date_time) + 3600*DATEPART(HOUR, Date_time)) AS Total_time FROM Test_Per ) AS A
MyTable: ID | Date_time SELECT A.Total_time/3600 AS 'Hour', (A.Total_time - (A.Total_time/3600)*3600)/60 AS 'Minutes', (A.Total_time - ((A.Total_time/3600)*3600) - ((A.Total_time - (A.Total_time/3600)*3600)/60)*60) AS 'Second' FROM ( SELECT SUM( DATEPART(SECOND, Date_time) + 60*DATEPART(MINUTE, Date_time) + 3600*DATEPART(HOUR, Date_time)) AS Total_time FROM Test_Per ) AS A
You appear to have placed your dates and times into separate columns which complicates the wanted arithmetic. So, the following combines the logindate with logintime and the same for logout data. Then a difference in seconds can be calculated (per row) or aggregated (as displayed here).
I have employed a CROSS APPLY to perform most of the calculations, this is done purely to allow re-use of the result by the alias ca.duration at output. I also attempt to display simpler subqueries to help trace the logic.
nb: I am using the same final display logic Cory used in his answer before mine.
MS SQL Server 2008 Schema Setup :
CREATE TABLE lgu00
([logindate] date, [logintime] time, [logoutdate] date, [logouttime] time)
;
INSERT INTO lgu00
([logindate], [logintime], [logoutdate], [logouttime])
VALUES
('2015-10-05', '09:00:00', '2015-10-10', '11:01:10'),
('2015-10-07', '09:00:00', '2015-10-10', '12:02:01'),
('2015-10-06', '09:00:00', '2015-10-10', '13:03:20'),
('2015-10-08', '09:00:00', '2015-10-10', '14:04:02'),
('2015-10-09', '09:00:00', '2015-10-10', '15:05:30'),
('2015-10-10', '09:00:00', '2015-10-10', '16:06:03'),
('2015-10-11', '09:00:00', '2015-10-11', '17:07:40')
;
Query 1 :
select
RIGHT('0' + CONVERT(VARCHAR(6), SUM(ca.duration) / 3600 ), 2 )
+ ':'
+ RIGHT('0' + CONVERT(VARCHAR(2), SUM(ca.duration) % 3600 / 60 ), 2 )
+ ':'
+ RIGHT('0' + CONVERT(VARCHAR(2), SUM(ca.duration) % 60 ), 2 )
AS [hh:mm:ss]
, SUM(ca.duration) AS [In Seconds]
FROM lgu00 t
CROSS APPLY (
SELECT DATEDIFF(second
, DATEADD(day,DATEDIFF(day,0,t.logindate),cast(t.logintime AS datetime))
, DATEADD(day,DATEDIFF(day,0,t.logoutdate),cast(t.logouttime AS datetime))
)
) ca (duration)
WHERE t.logindate >= '20150101' AND t.logoutdate < '20151101'
Results :
| hh:mm:ss | In Seconds |
|----------|------------|
| 95:29:46 | 1423786 |
Query 2 :
select
login
, logout
from lgu00
cross apply (
select
dateadd(day,datediff(day,0,logindate),cast(logintime as datetime)) as login
, dateadd(day,datediff(day,0,logoutdate),cast(logouttime as datetime)) as logout
) ca1
cross apply (
select datediff(second,ca1.login,ca1.logout) as duration
) ca2
Results :
| login | logout |
|---------------------------|---------------------------|
| October, 05 2015 09:00:00 | October, 10 2015 11:01:10 |
| October, 07 2015 09:00:00 | October, 10 2015 12:02:01 |
| October, 06 2015 09:00:00 | October, 10 2015 13:03:20 |
| October, 08 2015 09:00:00 | October, 10 2015 14:04:02 |
| October, 09 2015 09:00:00 | October, 10 2015 15:05:30 |
| October, 10 2015 09:00:00 | October, 10 2015 16:06:03 |
| October, 11 2015 09:00:00 | October, 11 2015 17:07:40 |
Query 3 :
select
duration
from lgu00
cross apply (
select datediff(second
, dateadd(day,datediff(day,0,logindate),cast(logintime as datetime))
, dateadd(day,datediff(day,0,logoutdate),cast(logouttime as datetime))
)
) ca (duration)
Results :
| duration |
|----------|
| 439270 |
| 270121 |
| 360200 |
| 191042 |
| 108330 |
| 25563 |
| 29260 |
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.