找到日期差异的最佳方法是什么?

时间:2015-08-10 07:32:31

标签: sql sql-server sql-server-2008

我有一个操作员表,我想计算一整天两个状态(10-20)之间的时差。 enter image description here

这里我想要" ActivityStatus"之间的时差。 10和20。 我们在这张照片中共有3组10-20状态。对于最后一个状态,在这种情况下没有20状态它将采用最后一个oa_createdDate(即oa_id 230141)。

此运算符的预期输出是cl_id 230096和230102之间的日期差异,cl_id 230103和230107之间的日期差异,cl_id 230109和cl_id 230141之间的日期差异。一旦我得到这些差异,我想将所有日期差异值加总到计算该运营商的繁忙时间。

提前致谢。

6 个答案:

答案 0 :(得分:1)

我怀疑DateDiff()函数是你寻找的函数

http://www.w3schools.com/sql/func_datediff.asp

答案 1 :(得分:1)

有一种简单的方法可以做我认为你想做外部应用的事情,就像这样:

select tmin.*, t.oa_CreateDate oa_CreateDate_20
    , datediff(minute, tmin.oa_CreateDate, t.oa_CreateDate) DiffInMinutes
from testtable t
cross apply 
    (select top 1 * 
    from testtable tmin 
    where tmin.oa_CreateDate < t.oa_CreateDate and tmin.oa_OperatorId = t.oa_OperatorId
    order by tmin.oa_CreateDate asc) tmin
where t.ActivityStatus = 20
and t.oa_CreateDate < (select min(oa_CreateDate) from testtable where ActivityStatus = 10 and oa_OperatorId = 1960)
and t.oa_OperatorId = 1960 
union all
select t.*
    , coalesce(a.oa_CreateDate,ma.MaxDate) oa_CreateDate_20 
    , datediff(minute, t.oa_CreateDate, coalesce(a.oa_CreateDate,ma.MaxDate)) DiffInMinutes
from testtable t
outer apply 
    (select top 1 a.oa_CreateDate
    from testtable a
    where a.oa_OperatorId = t.oa_OperatorId and a.ActivityStatus = 20 
    and t.oa_CreateDate < a.oa_CreateDate order by a.oa_CreateDate asc) a
outer apply 
  (select max(a2.oa_CreateDate) maxDate
  from testtable a2 
  where a2.oa_OperatorId = t.oa_OperatorId
  and t.oa_CreateDate < a2.oa_CreateDate) ma
where oa_OperatorId = 1960 
and ActivityStatus = 10
order by oa_CreateDate asc, oa_CreateDate_20 asc

你可以看到小提琴here

但是,当然,你必须给我们格式/ accurracy for datediff比较。这假设您将始终同时具有状态10和20,并且它们的时间戳范围永远不会重叠。

编辑:根据您的评论更新答案,检查新脚本并提琴。现在脚本填充找到所有状态10 - 20日期值,如果在最后10个之后没有状态20,则将使用该状态10之后的最新现有时间戳。

编辑2:更新了以下评论。但在这一点上,剧本变得相当丑陋。不幸的是我没有时间来清理它,所以我要求你下次发一个问题时,请尽可能清楚地把它弄清楚,因为这样做的回答要少得多。问题一次,而不是沿着骑行编辑3个不同的变化。 :)

无论如何,这应该可行,脚本中UNION ALL之前的新部分只有在没有前面10的状态20的情况下才会返回结果。否则它将不返回任何内容,并像以前一样移动到脚本的主要部分。小提琴也已更新。

答案 2 :(得分:0)

这是一种做法。

第一个OUTER APPLY将检索当前创建的日期时间之后状态为20的下一行。

第二个OUTER APPLY将检索当前创建的日期时间之后没有状态20的下一行。

SELECT
    o.*
    , COALESCE(NextStatus.oa_CreateDate, NextStatusIsNull.oa_CreateDate) AS NextTimestamp
    , COALESCE(NextStatus.ActivityStatus, NextStatusIsNull.ActivityStatus) AS NextStatus
    , DATEDIFF(MINUTE, o.oa_CreateDate,
            COALESCE(NextStatus.oa_CreateDate, NextStatusIsNull.oa_CreateDate))
    AS DifferenceInMinutes

FROM
    operators AS o
    OUTER APPLY
    (
        SELECT TOP 1
            oa_CreateDate
            , ActivityStatus

        FROM
            operators

        WHERE
            ActivityStatus = 20
            AND oa_CreateDate > o.oa_CreateDate

        ORDER BY
            oa_CreateDate
    ) AS NextStatus
    OUTER APPLY
    (
        SELECT TOP 1
            oa_CreateDate
            , ActivityStatus

        FROM
            operators

        WHERE
            NextStatus.oa_CreateDate IS NULL
            AND oa_CreateDate > o.oa_CreateDate

        ORDER BY
            oa_CreateDate
    ) AS NextStatusIsNull

WHERE
    ActivityStatus = 10

答案 3 :(得分:0)

我使用了一些不同的测试数据,因为您使用了我无法剪切和粘贴的图片。这应该很容易转换为您的表格:

请注意,这也适用于不存在的开始和结束日期

另请注意,这样做没有任何连接来优化性能。

测试表和数据:

DECLARE @t table(ActivityStatus int, oa_createdate datetime, oa_operatorid int)

INSERT @t values
(30, '2015-07-23 08:20', 1960),(20, '2015-07-23 08:24', 1960),
(10, '2015-07-23 08:30', 1960),(20, '2015-07-23 08:40', 1960),
(10, '2015-07-23 08:50', 1960),(50, '2015-07-23 09:40', 1960)

查询:

;WITH cte as
(
  SELECT
    ActivityStatus, 
    oa_createdate,
    oa_operatorid
  FROM @t
  WHERE ActivityStatus in (10,20)
  UNION ALL
  SELECT 20, max(oa_createdate), oa_operatorid
  FROM @t
  GROUP BY oa_operatorid
  HAVING 
    max(case when ActivityStatus = 20 then oa_createdate end) <
    max(case when ActivityStatus = 10 then oa_createdate end)
  UNION ALL
  SELECT 10, min(oa_createdate), oa_operatorid
  FROM @t
  GROUP BY oa_operatorid
  HAVING
    min(case when ActivityStatus = 20 then oa_createdate end) <  
    min(case when ActivityStatus = 10 then oa_createdate else '2999-01-01' end)
)
SELECT 
  cast(cast(sum(case when activitystatus = 10 then -1 else 1 end 
  * cast(oa_createdate as float)) as datetime) as time(0)) as difference_in_time,
  oa_operatorid
FROM cte
GROUP BY oa_operatorid

结果:

difference_in_time  oa_operatorid
01:04:00            1960

答案 4 :(得分:0)

数据

create table #Table2 (oa_id int, oa_OperatorId int, ActivityStatus int, oa_CreateDate datetime)

insert into #Table2 
values (1, 1960,10,'2015-08-10 10:55:12.317')   
    ,(2, 1960,20,'2015-08-10 11:55:12.317')
    ,(3, 1960,30,'2015-08-10 14:55:12.317')
    ,(4, 1960,50,'2015-08-10 14:58:12.317')
    ,(5, 1960,10,'2015-08-10 15:55:12.317')
    ,(6, 1960,20,'2015-08-10 16:20:12.317')
    ,(7, 1960,10,'2015-08-10 16:30:12.317')
    ,(8, 1960,50,'2015-08-10 17:20:12.317')

使用我们感兴趣的行填充目标表

select oa_id, 
       oa_operatorid, 
       ActivityStatus, 
       oa_createDate, 
       rn = row_number() over (order by oa_id desc) 
into #Table 
from #Table2 
where ActivityStatus in (10, 20)

insert #Table
select top 1 
       oa_id, 
       oa_operatorid, 
       ActivityStatus, 
       oa_createDate, 
       0 
from #Table2 
order by oa_id desc

select * into #Table10 from #Table where ActivityStatus = 10

select * into #Table20 from #Table where ActivityStatus = 20
union
select * from #Table where rn = 0 /*add the last record*/
except
select * from #Table where rn = (select max(rn) from #Table) /**discard the first "20" record*/


/*free time info*/
select datediff(second, t10.oa_createDate, t20.oa_createDate) secondssincelast10, 
t20.* 
from #Table10 t10 join #Table20 t20
on t10.rn = t20.rn + 1
and t10.oa_OperatorId = t20.oa_OperatorId


/*Summarized info per operator*/
select sum(datediff(second, t10.oa_createDate, t20.oa_createDate)) totalbusytime, 
t20.oa_OperatorId
from #Table10 t10 join #Table20 t20
on t10.rn = t20.rn + 1
and t10.oa_OperatorId = t20.oa_OperatorId
group by t20.oa_OperatorId

答案 5 :(得分:-1)

最好的方式

DATEDIFF(expr1,expr2)

示例:

  CREATE TABLE pins
    (`id` int, `time` datetime)
;

INSERT INTO pins
    (`id`, `time`)
VALUES
    (1, '2013-11-15 05:25:25')
;
SELECT DATEDIFF(CURDATE(), `time`)
FROM `pins`