What's the best way to find the difference in dates?

I have a table for statements in which I want to calculate the time difference between two states (10-20) for the whole day. enter image description here

Here I want the time difference between "ActivityStatus" 10 and 20. we have a total of 3 groups of 10-20 statuses. there is no status 20 for the last status, in which case it will take the last oa_createdDate (i.e. oa_id 230141).

My expected output for this statement is date diff between cl_id 230096 and 230102, date diff between cl_id 230103 and 230107, date diff between cl_id 230109 and cl_id 230141. Once I get this difference, I want to sum all date values ​​to calculate the occupied time for this operator.

Thanks in advance.

+3


source to share


6 answers


I have a suspicious suspicion that the DateDiff () function is the function you are looking for



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

+1


source


There's an easy way to do what I assume you want to do with the external one, for example:

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

      

You can see the script here .

But of course you have to give us the format / clarity for a dated comparison. And that assumes that you will always have status 10 and 20 and that their timestamps never overlap.



EDIT: Updated answer based on your comment, check out new script and fiddle. The fill script now finds all status 10-20 points, and in case there is no status 20 after the last 10, the last existing timestamp after that state 10 will be used instead.

EDIT 2: Updated with your comment below. But at this point, the script is getting pretty ugly. Unfortunately, I don't have time to clean it up, so I ask that next time you post a question please make it as clear and clean as possible, as there are 3 different ride options when trying to answer the question. :)

This should work one way or another, a new section before UNION ALL in the script will only return results if there is a status of 20 with no preceding 10. Otherwise it will return nothing and will move to the main script part as before. Fiddle has been updated as well.

+1


source


This is one way to do it.

The first OUTER APPLY

will fetch the next line with status 20 that is after the currently created datetime.

The second one OUTER APPLY

will retrieve the next line after the currently created datetime where there is no status 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

      

0


source


I used several different test data because you were using an image that I was unable to cut and paste from. It's easy to convert to a table:

Note that this should also work with missing start and end dates,

Also note that this was done without any joins to optimize performance.

Test table and data:

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)

      

Query:

;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

      

Result:

difference_in_time  oa_operatorid
01:04:00            1960

      

0


source


Data

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

      

Set the target table with the rows that interest us

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

      

0


source


The best way

DATEDIFF(expr1,expr2)

      

Example:

  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`

      

-1


source







All Articles