在sql中计算总时间hh:mm:ss

时间:2015-10-12 21:27:56

标签: sql sql-server datetime datediff

我正在尝试计算桌子上的总小时数。但是当总时间超过24小时时,我得到了错误的结果。让我们说总小时是30但这个查询计算它6.另一件事是如果总时间少于24小时它给出了正确的结果。 你能救我吗?

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

4 个答案:

答案 0 :(得分:0)

我相信我从Adam Machanic's sp_whoisactive存储过程中获取了以下内容。

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'

答案 1 :(得分:0)

sql server中的time类型最多只能容纳24小时。因此,您需要转换为datetime,然后进行计算以转换为小时:分钟:秒。

此外,您需要在数据中包含您的年份,否则如果有人在年度更改之前登录,然后在之后退出,则会产生非常大的负差异。

这是一个例子......我使用公用表表达式来计算两个日期之间的差异,然后报告所需格式的总差异。

;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

此外,如果你需要你的分钟和小时来获得前导零,这就是我在最终选择中会这样做的方式:

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

答案 2 :(得分:0)

假设我有一张桌子喜欢 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

答案 3 :(得分:0)

您似乎已将日期和时间放在单独的列中,这使得所需的算术变得复杂。因此,以下内容将logindate与logintime相结合,对于注销数据也是如此。然后可以计算(每行)或聚合(如此处显示)的秒数差异。

我使用了CROSS APPLY来执行大部分计算,这纯粹是为了允许在输出处通过别名 ca.duration 重复使用结果。我还尝试显示更简单的子查询以帮助跟踪逻辑。

nb:我正在使用与他之前的答案中使用的相同的最终显示逻辑Cory。

SQL Fiddle

MS SQL Server 2008架构设置

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')
;

查询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 |

查询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 |

查询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 |