SQL Time Tracking Query
Data:
EmpNumber, TimeStamp, AreaName 10632, 2009-11-23 16:40:33.000, OUT_1 10632, 2009-11-23 16:39:03.000, IN_1 10632, 2009-11-23 16:38:56.000, IN_1 10632, 2009-11-23 15:31:51.000, OUT_1 10632, 2009-11-23 15:31:48.000, IN_1 10632, 2009-11-23 15:31:43.000, IN_1 10632, 2009-11-23 15:31:14.000, OUT_1 10632, 2009-11-23 15:31:08.000, IN_1 10632, 2009-11-23 15:29:18.000, OUT_1 10632, 2009-11-23 15:28:29.000, IN_1 10632, 2009-11-23 15:27:35.000, OUT_1 10632, 2009-11-23 15:26:35.000, IN_1 10632, 2009-11-23 15:22:55.000, IN_1
Here is the query I am currently using.
SELECT [EmpNumber], [TimeStamp], [AreaName],
DATEDIFF(second, [TimeStamp], (SELECT TOP 1 [TimeStamp]
FROM [EventTable] EV2
WHERE EV2.[TimeStamp] > EV1.[TimeStamp]
AND AreaName = 'OUT_1'
AND EV2.[EmpNumber] = EV1.[EmpNumber])
开发者_运维知识库 )/60.00 DurationMins
FROM [EventTable] EV1
WHERE AreaName = 'IN_1'
ORDER BY [TimeStamp] DESC
The problem is on the multiple IN_1
entries. I would only like to track the time difference between the first IN_1
Entry, and the Following OUT_1
Entry and Ignore the IN_1
entry in between. Of course you could have 100 IN_1
but the time is only tracked from the first IN_1
to the next OUT_1
.
To complicate things further there could be an IN_1
, IN_2
, IN_3
, OUT_1
, OUT_2
, OUT_3
and you could enter IN_1
and Leave OUT_3
and and it would work just as it was IN_1
, OUT_1
.
Solved
declare @test table (
ID int,
empnumber int,
timestamp datetime,
areaname varchar(20)
)
INSERT INTO @test VALUES (1, 10632, '2009-11-23 16:40:33.000', 'OUT_1' )
INSERT INTO @test VALUES (2, 10632, '2009-11-23 16:39:03.000', 'IN_1' )
INSERT INTO @test VALUES (3, 10632, '2009-11-23 16:38:56.000', 'IN_1' )
INSERT INTO @test VALUES (4, 10632, '2009-11-23 15:31:51.000', 'OUT_1' )
INSERT INTO @test VALUES (5, 10632, '2009-11-23 15:31:48.000', 'IN_1' )
INSERT INTO @test VALUES (6, 10632, '2009-11-23 15:31:43.000', 'IN_1' )
INSERT INTO @test VALUES (7, 10632, '2009-11-23 15:31:14.000', 'OUT_1' )
INSERT INTO @test VALUES (8, 10632, '2009-11-23 15:31:08.000', 'IN_1' )
INSERT INTO @test VALUES (9, 10632, '2009-11-23 15:29:18.000', 'OUT_1' )
INSERT INTO @test VALUES (10, 10632, '2009-11-23 15:28:29.000', 'IN_1' )
INSERT INTO @test VALUES (11, 10632, '2009-11-23 15:27:35.000', 'OUT_1' )
INSERT INTO @test VALUES (12, 10632, '2009-11-23 15:26:35.000', 'IN_1' )
INSERT INTO @test VALUES (13, 10632, '2009-11-23 15:22:55.000', 'IN_1' )
select g.empnumber, min(g.[timestamp]) as starttime, g.[timeout] as endtime, DATEDIFF(second,min(g.[timestamp]),g.[timeout])/60 as mins
FROM
(
select empnumber, [timestamp], (
SELECT TOP 1 s.[timestamp] FROM @test s
WHERE s.areaname like 'OUT%' AND s.[timestamp] > base.[timestamp]
ORDER BY s.[timestamp] ASC) as [timeout]
from @test base
where base.areaname like 'IN%'
) g
GROUP BY g.empnumber, g.[timeout]
Gives these results:
empnumber starttime endtime mins
10632 2009-11-23 15:22:55.000 2009-11-23 15:27:35.000 4
10632 2009-11-23 15:28:29.000 2009-11-23 15:29:18.000 0
10632 2009-11-23 15:31:08.000 2009-11-23 15:31:14.000 0
10632 2009-11-23 15:31:43.000 2009-11-23 15:31:51.000 0
10632 2009-11-23 16:38:56.000 2009-11-23 16:40:33.000 1
This will work for all types if IN_ and OUT_
Nick, the different doors are not an issue instead of using = 'IN_1'
and = 'OUT_1'
use like 'IN%'
and like 'OUT%'
CTEs will work on SQL server 2005, 2008. The test data insert is 2008 specific.
DECLARE @EventTable TABLE
(
EmpNumber int
,[TimeStamp] datetime
,AreaName varchar(5)
)
INSERT INTO @EventTable
( EmpNumber, [TimeStamp], AreaName )
VALUES
( 10632, '2009-11-23 16:40:33.000', 'OUT_1' )
, ( 10632, '2009-11-23 16:39:03.000', 'IN_1' )
, ( 10632, '2009-11-23 16:38:56.000', 'IN_1' )
, ( 10632, '2009-11-23 15:31:51.000', 'OUT_1' )
, ( 10632, '2009-11-23 15:31:48.000', 'IN_1' )
, ( 10632, '2009-11-23 15:31:43.000', 'IN_1' )
, ( 10632, '2009-11-23 15:31:14.000', 'OUT_1' )
, ( 10632, '2009-11-23 15:31:08.000', 'IN_1' )
, ( 10632, '2009-11-23 15:29:18.000', 'OUT_1' )
, ( 10632, '2009-11-23 15:28:29.000', 'IN_1' )
, ( 10632, '2009-11-23 15:27:35.000', 'OUT_1' )
, ( 10632, '2009-11-23 15:26:35.000', 'IN_1' )
, ( 10632, '2009-11-23 15:22:55.000', 'IN_1' )
;
WITH cte_1 -- order by time and spilt to InTime, OutTime
AS ( SELECT
EmpNumber
,case WHEN AreaName LIKE 'IN%' THEN [TimeStamp]
ELSE NULL
END AS InTime
,case WHEN AreaName LIKE 'OUT%' THEN [TimeStamp]
ELSE NULL
END AS OutTime
,AreaName
,row_number() OVER ( ORDER BY [TimeStamp] ASC ) AS rn
FROM
@EventTable
),
cte_2 -- mark those that repeat
AS ( SELECT
t.EmpNumber
,t.InTime
,t.OutTime
,t.AreaName
,t.rn
,case WHEN ( SELECT AreaName
FROM cte_1 AS x
WHERE x.rn = t.rn - 1
) = t.AreaName THEN 1
ELSE 0
END AS mrk
FROM cte_1 AS t
),
cte_3 --extract non repeats and group
AS ( SELECT
*
,row_number() OVER ( PARTITION BY AreaName ORDER BY rn ASC ) AS rn2
FROM cte_2
WHERE mrk = 0
)
SELECT
t1.EmpNumber
,t1.InTime
,t2.Outtime
,datediff(ss, t1.InTime, t2.OutTime) AS Duration
FROM
cte_3 AS t1
JOIN cte_3 AS t2 ON t1.rn2 = t2.rn2
WHERE
t1.Intime IS NOT NULL
AND t2.Outtime IS NOT NULL
ORDER BY
t1.rn
精彩评论