2009-11-24 9 views
0

données:SQL Suivi des requêtes

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

Voici la requête que je utilise actuellement. Le problème est sur les entrées IN_1 multiples. Je voudrais seulement suivre la différence de temps entre la première entrée IN_1 et l'entrée suivante OUT_1 et ignorer l'entrée IN_1 entre. Bien sûr, vous pouvez avoir 100 IN_1 mais le temps n'est suivi qu'à partir du premier IN_1 jusqu'au prochain OUT_1.

Pour compliquer encore les choses, il pourrait être un IN_1, IN_2, IN_3, OUT_1, OUT_2, OUT_3 et vous pouvez entrer IN_1 et laisser OUT_3 et il fonctionnerait comme il était IN_1, OUT_1.

+0

Je ne suis pas le bit "Pour compliquer les choses". Aussi, quelle est votre question? –

+0

Je ne suis pas très clair sur ce que vous voulez faire, mais je suppose (si vous utilisez tsql 2005+) vous devez utiliser un CTE récursif ou une boucle. – Hogan

+0

C'est le suivi du temps sur le contrôle d'accès. Quelqu'un pourrait glisser une carte deux fois sur un lecteur IN_1. Le problème est quand j'exécute la requête ci-dessus je reçois deux DurationMins différents en utilisant le premier et le deuxième balayage. Donc, au lieu de signaler que quelqu'un était dans 1.616 minutes, ils sont dans 1.616 et 1.5 (en utilisant l'exemple ci-dessus). Donc, pour compliquer les thigns un peu plus, cela montre juste qu'ils pourraient venir dans une des 3 portes d'entrée et partir de n'importe quelle porte qu'ils choisissent. Cela ne devrait pas être un gros problème, mais tout ce que je fais doit aussi pouvoir fonctionner correctement dans cette situation. – Nick

Répondre

1

Résolu

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] 

donne à ces résultats:

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 

Cela fonctionne pour tous les types si IN_ et OUT_

+0

Qu'en est-il du cas où la carte est glissée deux fois à la sortie? – Joel

+0

changez g [timeout] comme endtime en max (g. [Timeout]) comme temps de fin et sortez-le du groupe par l'instruction. – Hogan

+0

hmmm ... ça ne marchera pas. une seconde. – Hogan

1

Nick, les différentes portes ne sont pas un problème au lieu d'utiliser = 'IN_1' et = 'OUT_1' utilisation like 'IN%' et like 'OUT%'

+0

Je suis d'accord .. Je vous avez besoin de trouver des intervalles entre: IN_1 <-> OUT_3 vous ne pouvez tout simplement pas le faire comme il est configuré maintenant. Envisagez également d'ajouter une colonne supplémentaire pour signaler si l'entrée de ligne est un événement IN ou un événement OUT. De cette façon, vous n'aurez besoin que de trouver la prochaine ligne OUT pour connaître l'heure de sortie, quelle que soit la porte utilisée. – Radu094

0

Les CTE fonctionneront sur le serveur SQL 2005, 2008. L'insertion de données de test est spécifique à 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