2009-11-24 1 views
0

данных:SQL Time Tracking Запрос

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

Вот запрос я в настоящее время использую.

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 

Проблема заключается в нескольких вводах IN_1. Я хотел бы просто отслеживать разницу во времени между первой записью IN_1 и следующей записью OUT_1 и игнорировать запись IN_1. Конечно, вы могли бы иметь 100 IN_1, но время отслеживается только с первых IN_1 до следующего OUT_1.

усложнять дальше могло быть IN_1, IN_2, IN_3, OUT_1, OUT_2, OUT_3 и вы можете ввести IN_1 и оставьте OUT_3 и и он будет работать так же, как это было IN_1, OUT_1.

+0

Я не следую за «усложнить ситуацию». Также, каков ваш вопрос? –

+0

Я не совсем понимаю, что вы хотите сделать, но я ожидаю (если вы используете tsql 2005+), вам нужно использовать рекурсивный CTE или цикл. – Hogan

+0

Это отслеживание времени при управлении доступом. Кто-то может дважды щелкнуть карту на считывателе IN_1. Проблема в том, что когда я запускаю запрос выше, я получаю два разных DurationMins с использованием Первого и Второго салфетки. Таким образом, вместо того, чтобы сообщать, что кто-то был в течение 1.616 минут, они заняты 1.616 и 1.5 (используя пример выше). Таким образом, чтобы усложнить разглагольствование, это просто показывает, что они могут войти в одну из 3 входных дверей и выйти из любой двери, которую они выбирают. Это не должно быть большой проблемой, но все, что мне нужно, также должно быть в состоянии правильно работать в этой ситуации. – Nick

ответ

1

Решенные

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] 

дает следующие результаты:

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 

Это будет работать для все типы, если IN_ и OUT_

+0

Как насчет случая, когда карта дважды выжимается при выходе? – Joel

+0

измените g. [Timeout] как конечное время до max (g. [Timeout]) в качестве конечного времени и выведите его из оператора по команде. – Hogan

+0

hmmm ... это не сработает. одну секунду. – Hogan

1

Ник, различные двери не проблема, вместо того чтобы использовать = 'IN_1' и = 'OUT_1' использования like 'IN%' и like 'OUT%'

+0

Я согласен. Мне нужно найти промежутки между: IN_1 <-> OUT_3 вы просто не можете сделать это, как сейчас. Рассмотрим также добавление дополнительного столбца, чтобы сигнализировать, является ли запись строки IN или событием OUT. Таким образом, вам нужно будет найти следующую строку OUT, чтобы узнать время выхода, независимо от используемой двери. – Radu094

0

CTE будут работать на SQL Server 2005, 2008. Вставка тестовых данных относится к 2008 году.

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