Pregunta

Estoy escribiendo un programa simple de seguimiento del tiempo para administrar mis propios proyectos. Soy un gran admirador de mantener el código de informes en la base de datos, por lo que he intentado crear algunos sprocs que generan las facturas y las hojas de tiempo, etc.

Tengo una tabla que contiene acciones de reloj, IE " Punch In " ;, y " Punch Out " ;. También contiene el usuario que realizó esta acción, el proyecto asociado con la acción y la fecha / hora actual.

Puedo seleccionar de esta tabla para obtener entradas de reloj para un tiempo / proyecto / usuario específico, pero quiero agregarlo hacia abajo para que cada entrada y salida de reloj se convierta de 2 filas a una sola fila que contenga el tiempo total.

Por ejemplo, aquí hay una salida de muestra:

ClockActionID        ActionType DateTime
-------------------- ---------- -----------------------
17                   1          2008-11-08 18:33:56.000
18                   2          2008-11-08 18:33:59.587
19                   1          2008-11-08 18:34:01.023
20                   2          2008-11-08 18:34:02.037
21                   1          2008-11-08 18:45:06.317
22                   2          2008-11-08 18:46:14.597
23                   1          2008-11-08 18:46:16.283
24                   2          2008-11-08 18:46:17.173
25                   1          2008-11-08 18:50:37.830
26                   2          2008-11-08 18:50:39.737
27                   1          2008-11-08 18:50:40.547

(11 row(s) affected)

Donde ActionType 1 es & Clock; ClockIn " y ActionType 2 es "ClockOut". También eliminé las columnas Usuario, Proyecto y Descripción por brevedad.

Necesito generar, en SQL puro, un conjunto de resultados como:

Description   |    Total Time

Para cada par ClockIn / ClockOut.

Supongo que esto será bastante simple, simplemente no estoy seguro de qué manera abordarlo.

EDITAR: El usuario podrá acceder a múltiples proyectos simultáneamente, aunque al reducir primero el conjunto de resultados a un solo proyecto, esto no debería hacer ninguna diferencia en la lógica aquí.

¿Fue útil?

Solución

Estoy de acuerdo en que el diseño no es el mejor: una estructura basada en eventos con una sola fila para el inicio y el final probablemente le ahorrará mucho tiempo. En ese caso, podría crear un registro con una fecha de finalización nula cuando alguien registre la entrada. Luego, complete la fecha de finalización cuando se desconecte.

Pero, eso no es lo que preguntaste. Esta es la solución a su problema:

DECLARE @clock TABLE (ClockActionID INT PRIMARY KEY IDENTITY, ActionType INT, ActionDateTime DATETIME)

INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:00:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:01:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:02:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:03:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:04:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:05:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:06:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:07:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:08:12')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:09:00')

-- Get the range
SELECT ActionDateTime CheckIn, 
  (SELECT TOP 1 ActionDateTime 
   FROM @clock C2 
   WHERE C2.ActionDateTime > C.ActionDateTime) CheckOut   
FROM @clock C
WHERE ActionType = 1

-- Get the duration
SELECT DATEDIFF(second, ActionDateTime, 
  (SELECT TOP 1 ActionDateTime 
   FROM @clock C2 
   WHERE C2.ActionDateTime > C.ActionDateTime)
  ) / 60.0 Duration_Minutes
FROM @clock C
WHERE ActionType = 1

Tenga en cuenta que estoy usando una variable de tabla que funciona con MS SQL Server solo para probar. Cambiar según sea necesario. También tenga en cuenta que SQL Server 2000 no funciona bien con consultas como esta. Aquí están los resultados de la prueba:

CheckIn                 CheckOut
2008-01-01 00:00:00.000 2008-01-01 00:01:00.000
2008-01-01 00:02:00.000 2008-01-01 00:03:00.000
2008-01-01 00:04:00.000 2008-01-01 00:05:00.000
2008-01-01 00:06:00.000 2008-01-01 00:07:00.000
2008-01-01 00:08:12.000 2008-01-01 00:09:00.000

Duration_Minutes
1.000000
1.000000
1.000000
1.000000
0.800000

Otros consejos

Creo que su esquema de almacenamiento original es defectuoso. Lo estás mirando desde la perspectiva del reloj, de ahí ClockAction. ¿Por qué no desde la perspectiva del proyecto?

TABLE ProjectAction (Projectid, Userid, Type, Start, End)

Entonces un simple GROUP BY debería hacer el truco.

¿Has pensado en cosas como:

  • alguien se olvida del reloj y, por lo tanto, parece que lo hicieron dos veces.
  • alguien se olvida de entrar y, por lo tanto, ¿parece que salieron dos veces?

En el primer caso, ¿es correcto simplemente ignorar la segunda entrada? La respuesta aceptada vinculará ambas entradas a la misma salida. ¿Es eso correcto?

En el segundo caso, se ignorará el segundo tiempo de espera. ¿Es eso correcto?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top