2016-08-08 39 views
-1

Ich habe eine Tabelle mit dem Namen DeviceLogs_8_2016, in der alle Aufzeichnungen von In-Time- und Out-Time-Aufzeichnungen von Mitarbeitern gespeichert sind.Berechne die Dauer und die Dauer des Mitarbeiters

Tabellenname ändert sich jeden Monat. Ex: Die Aufzeichnungen von 2016-09-01 0:00:00 würde in Tabelle DeviceLogs_9_2016

Tabelle enthält Aufzeichnungen aller Mitarbeiter wie unter dem Namen gespeichert werden, aber ich brauche nur einen einzelne Benutzer-ID an einem bestimmten Datum.

+--------+---------------------+-----------+ 
| UserId |  LogDate  | Direction | 
+--------+---------------------+-----------+ 
| 7034 | 2016-08-08 08:21:14 | in  | 
| 5012 | 2016-08-08 08:21:26 | out  | 
| 7036 | 2016-08-08 08:21:34 | in  | 
| 7034 | 2016-08-08 10:01:14 | in  | 
| 8015 | 2016-08-08 10:10:39 | in  | 
| 2055 | 2016-08-08 10:11:27 | in  | 
| 209 | 2016-08-08 11:28:25 | out  | 
| 209 | 2016-08-08 11:32:32 | in  | 
| 11253 | 2016-08-08 12:35:17 | out  | 
| 7034 | 2016-08-08 12:37:58 | in  | 
| 7034 | 2016-08-08 13:30:13 | out  | 
| 4586 | 2016-08-08 13:30:24 | in  | 
| 7034 | 2016-08-08 13:30:28 | out  | 
| 209 | 2016-08-08 13:35:36 | out  | 
+--------+---------------------+-----------+ 

Beispieldaten mit nur einzelne Benutzer-ID für den ganzen Tag ist, wie nachfolgend beschrieben

+--------+---------------------+-----------+ 
| UserId |  LogDate  | Direction | 
+--------+---------------------+-----------+ 
| 7034 | 2016-08-08 08:20:59 | in  | 
| 7034 | 2016-08-08 08:21:04 | in  | 
| 7034 | 2016-08-08 08:21:14 | in  | 
| 7034 | 2016-08-08 08:21:26 | out  | 
| 7034 | 2016-08-08 08:21:34 | in  | 
| 7034 | 2016-08-08 09:35:26 | out  | 
| 7034 | 2016-08-08 10:01:14 | in  | 
| 7034 | 2016-08-08 12:35:17 | out  | 
| 7034 | 2016-08-08 12:37:58 | in  | 
| 7034 | 2016-08-08 13:29:13 | out  | 
| 7034 | 2016-08-08 13:30:08 | out  | 
| 7034 | 2016-08-08 13:30:13 | out  | 
| 7034 | 2016-08-08 14:30:24 | in  | 
| 7034 | 2016-08-08 17:30:24 | out  | 
| 7034 | 2016-08-08 17:40:24 | in  | 
| 7034 | 2016-08-08 22:15:38 | out  | 
| 7034 | 2016-08-08 22:50:05 | in  | 
| 7034 | 2016-08-09 01:20:05 | out  | 
| 7034 | 2016-08-09 01:22:10 | in  | 
| 7034 | 2016-08-09 04:50:15 | out  | 
+--------+---------------------+-----------+ 

In Anbetracht der Teilnahme an diesem Tag von 2016-08-08 05:00:00 beginnt und endet an 2016-08-09 05:00:00.

Ich möchte die Gesamt-In-Duration und Gesamt-Out-Dauer des Mitarbeiters an diesem Tag berechnen. Wenn In oder Out kontinuierlich erscheint, können wir nur das letzte In vor Out und das erste Out vor In betrachten.

Ich möchte Ergebnis wie

+--------+------------+-------------+--------------+ 
| UserId | LogDate | In_Duration | Out_Duration | 
+--------+------------+-------------+--------------+ 
| 7034 | 2016-08-08 | 18:12:41 | 02:16:20  | 
+--------+------------+-------------+--------------+ 

ich die Berechnungen in einer Excel-Tabelle für die angegebenen Beispieldaten ausgearbeitet werden müssen.

╔═════════╦════════╦═════════════════════╦═══════════╦══════════╦══════════╦══════════════════╗ 
║ row_sno ║ UserId ║  LogDate  ║ Direction ║ In_Diff ║ Out_Diff ║ Diff_Calculation ║ 
╠═════════╬════════╬═════════════════════╬═══════════╬══════════╬══════════╬══════════════════╣ 
║  1 ║ 7034 ║ 2016-08-08 08:20:59 ║ in  ║   ║   ║     ║ 
║  2 ║ 7034 ║ 2016-08-08 08:21:04 ║ in  ║   ║   ║     ║ 
║  3 ║ 7034 ║ 2016-08-08 08:21:14 ║ in  ║   ║   ║     ║ 
║  4 ║ 7034 ║ 2016-08-08 08:21:26 ║ out  ║ 00:00:12 ║   ║ 4th - 3th row ║ 
║  5 ║ 7034 ║ 2016-08-08 08:21:34 ║ in  ║   ║ 00:00:08 ║ 5th - 4th row ║ 
║  6 ║ 7034 ║ 2016-08-08 09:35:26 ║ out  ║ 01:13:52 ║   ║ 6th - 5th row ║ 
║  7 ║ 7034 ║ 2016-08-08 10:01:14 ║ in  ║   ║ 00:25:48 ║ 7th - 6th row ║ 
║  8 ║ 7034 ║ 2016-08-08 12:35:17 ║ out  ║ 02:34:03 ║   ║ 8th - 7th row ║ 
║  9 ║ 7034 ║ 2016-08-08 12:37:58 ║ in  ║   ║ 00:02:41 ║ 9th - 8th row ║ 
║  10 ║ 7034 ║ 2016-08-08 13:29:13 ║ out  ║ 00:51:15 ║   ║ 10th - 9th row ║ 
║  11 ║ 7034 ║ 2016-08-08 13:30:08 ║ out  ║   ║   ║     ║ 
║  12 ║ 7034 ║ 2016-08-08 13:30:13 ║ out  ║   ║   ║     ║ 
║  13 ║ 7034 ║ 2016-08-08 14:30:24 ║ in  ║   ║ 01:01:11 ║ 13th - 10th row ║ 
║  14 ║ 7034 ║ 2016-08-08 17:30:24 ║ out  ║ 03:00:00 ║   ║ 14th - 13th row ║ 
║  15 ║ 7034 ║ 2016-08-08 17:40:24 ║ in  ║   ║ 00:10:00 ║ 15th - 14th row ║ 
║  16 ║ 7034 ║ 2016-08-08 22:15:38 ║ out  ║ 04:35:14 ║   ║ 16th - 15th row ║ 
║  17 ║ 7034 ║ 2016-08-08 22:50:05 ║ in  ║   ║ 00:34:27 ║ 17th - 16th row ║ 
║  18 ║ 7034 ║ 2016-08-09 01:20:05 ║ out  ║ 02:30:00 ║   ║ 18th - 17th row ║ 
║  19 ║ 7034 ║ 2016-08-09 01:22:10 ║ in  ║   ║ 00:02:05 ║ 19th - 18th row ║ 
║  20 ║ 7034 ║ 2016-08-09 04:50:15 ║ out  ║ 03:28:05 ║   ║ 20th - 19th row ║ 
║   ║  ║      ║   ║   ║   ║     ║ 
║   ║  ║      ║ TOTAL  ║ 18:12:41 ║ 02:16:20 ║     ║ 
╚═════════╩════════╩═════════════════════╩═══════════╩══════════╩══════════╩══════════════════╝ 
+0

Können Sie die Zeile hinzufügen, '7034 | 2016-08-09 00: 01: 14.000 | zu den Tabellendaten aus und passen Sie das erwartete Ergebnis an (falls erforderlich)? – jarlh

+0

Haben Sie Fälle von Kreuztag? Wie willst du damit umgehen? Welche Version von SQL Server verwenden Sie? – Squirrel

+0

Ja, Cross-Day-Fälle existieren. Die Schaltzeit des Tages beginnt um 5:00 Uhr und endet um 5:00 Uhr am nächsten Tag. Ich verwende SQL Server 2012 –

Antwort

1

diese Abfrage gibt das erwartete Ergebnis mit LAG() Funktion (schneller):

;with 
q0 as (
    SELECT 
     UserId, LogDate, Direction, 
     LAG(Direction) OVER (partition by userid ORDER BY LogDate) AS PreDirection 
     -- comment/uncomment below line to calc respectively from the first or the last `[in]` after `[out]` 
     -- comment = first, uncomment = last 
     , LAG(LogDate) OVER (partition by userid ORDER BY LogDate) AS PreLogDate 
    FROM DeviceLogs_8_2016 
), 
q as (
    select 
     UserId, LogDate, Direction, 
     -- rem/un-rem to calc respectively from the first or the last `[in]` after `[out]` 
     /* use this for first */ -- datediff(second, lag(LogDate) over (partition by userid order by logdate), LogDate) secs 
     /* use this for last */ datediff(second, PreLogDate, LogDate) secs 
    from q0 
    where Direction<>PreDirection or PreDirection is null 
), 
s as (
    select * 
    from q 
    pivot (SUM(secs) for Direction in ([in], [out])) as p 
) 
--/*DEBUG*/ select *, convert(time(0), dateadd(second, secs, 0)) duration from q order by userid, LogDate 
select 
    UserId, 
    convert(time(0), dateadd(second, SUM([out]), 0)) In_Duration, 
    convert(time(0), dateadd(second, SUM([in]), 0)) Out_Duration 
from s 
group by userid 

Ergebnis:

UserId In_Duration Out_Duration 
209  03:17:16 00:33:24 
7034 18:12:41 02:15:20 
+0

Ich konnte das erwartete Ergebnis nicht erhalten ....für eine andere Reihe von data.am Ich vermisse etwas ..? –

+0

Der einzige Unterschied ist der Name der Spalte [Direction], ich habe [Dir] benutzt, versuche es in meinem 'SELECT' umzubenennen. wenn immer noch nicht funktioniert, schreibt den neuen Satz von Daten, werde ich in sie aussehen – MtwStark

+0

'UserId \t LogDate \t Richtung 2016.08.08 10: 10: 34.000 \t in 2016.08.08 10 : 10: 39.000 \t in 2016.08.08 10: 10: 49.000 \t in 2016.08.08 10: 10: 51.000 \t in 2016.08.08 10: 11: 27.000 \t in 2016-08-08 11: 28: 25.000 \t aus 2016-08-08 11: 32: 32.000 \t in 2016.08.08 12: 25: 15.000 \t out 2016.08.08 12: 28: 01.000 \t in 2016.08.08 13: 35: 36.000 \t out 2016.08.08 14: 02: 07.000 \t in' –

-1
;WITH 
    Punch_logs_U as (SELECT distinct userid, logdate,direction from punch_logs), 
    IN_OUT_TIMES 
    AS (SELECT P1.USERID, 
     P1.LOGDATE, 
     P1.DIRECTION, 
     P2.Logdate Logdate_out, 
     P2.Direction Direction_out 
      FROM Punch_Logs_u P1 
      OUTER APPLY 
      (SELECT TOP 1 PC.Logdate, PC.Direction From Punch_Logs_u PC WHERE 
                PC.UserId = P1.UserId 
                AND 
                PC.Direction = 'OUT' 
                AND PC.Logdate >= P1.Logdate) P2 
      WHERE P1.Direction = 'IN' AND 
       NOT EXISTS (SELECT 0 FROM Punch_Logs_u P3 WHERE 
                   P3.UserID = P1.UserId 
                  AND P3.direction = 'IN' 
                  AND P3.logdate > P1.Logdate 
                  AND P3.Logdate <= P2.Logdate) 
     ) 
     SELECT IO.USERID, 
       IO.Logdate LogDate_in, 
       io.Logdate_out, 
       DATEDIFF(minute,io.logdate, io.logdate_out) TimeInMins , 
       DATEDIFF(minute,LAG(logdate, 1,io.logdate) over (partition by userid order by logdate), io.logdate) TimeOUTMins 

        FROM IN_OUT_TIMES IO order by userid, io.logdate 
+0

liefert diese Abfrage nicht die korrekte Ausgabe – MtwStark

1

Versuchen Sie, diese

DECLARE @Tbl TABLE (UserId INT, LogDate DATETIME, Direction NVARCHAR(50)) 
INSERT INTO @Tbl 
VALUES        
(7034 ,'2016-08-08 08:20:59', 'in'), 
(7034 ,'2016-08-08 08:21:04', 'in'), 
(7034 ,'2016-08-08 08:21:14', 'in'), 
(7034 ,'2016-08-08 08:21:26', 'out'), 
(7034 ,'2016-08-08 08:21:34', 'in'), 
(7034 ,'2016-08-08 09:35:26', 'out'), 
(7034 ,'2016-08-08 10:01:14', 'in'), 
(7034 ,'2016-08-08 12:35:17', 'out'), 
(7034 ,'2016-08-08 12:37:58', 'in'), 
(7034 ,'2016-08-08 13:29:13', 'out'), 
(7034 ,'2016-08-08 13:30:08', 'out'), 
(7034 ,'2016-08-08 13:30:13', 'out'), 
(7034 ,'2016-08-08 14:30:24', 'in'), 
(7034 ,'2016-08-08 17:30:24', 'out'), 
(7034 ,'2016-08-08 17:40:24', 'in'), 
(7034 ,'2016-08-08 22:15:38', 'out'), 
(7034 ,'2016-08-08 22:50:05', 'in'), 
(7034 ,'2016-08-09 01:20:05', 'out'), 
(7034 ,'2016-08-09 01:22:10', 'in'), 
(7034 ,'2016-08-09 04:50:15', 'out') 


;WITH CTE 
AS 
(
    SELECT 
     UserId , 
     LogDate , 
     Direction, 
     LAG(LogDate) OVER (ORDER BY LogDate) AS PreLogDate, 
     LAG(Direction) OVER (ORDER BY LogDate) AS PreDirection 
    FROM 
     @Tbl 
    WHERE 
     UserId = 7034 
) 

SELECT 
    A.UserId , 
    A.LogDate , 
    A.Direction , 
    IIF(In_Diff <> 0, 
     RIGHT('0' + CAST(In_Diff/3600 AS VARCHAR),2) + ':' + 
     RIGHT('0' + CAST((In_Diff/60) % 60 AS VARCHAR),2) + ':' + 
     RIGHT('0' + CAST(In_Diff % 60 AS VARCHAR),2), '') AS In_Diff , 
    IIF(Out_Diff <> 0, 
     RIGHT('0' + CAST(Out_Diff/3600 AS VARCHAR),2) + ':' + 
     RIGHT('0' + CAST((Out_Diff/60) % 60 AS VARCHAR),2) + ':' + 
     RIGHT('0' + CAST(Out_Diff % 60 AS VARCHAR),2), '') AS Out_Diff 
FROM 
(
    SELECT 
     CTE.UserId , 
     CTE.LogDate , 
     CTE.Direction , 
     IIF(CTE.Direction = 'out' AND CTE.PreDirection = 'in', DATEDIFF(SECOND, cte.PreLogDate, cte.LogDate), 0) AS In_Diff, 
     IIF(CTE.Direction = 'in' AND CTE.PreDirection = 'out', DATEDIFF(SECOND, cte.PreLogDate, cte.LogDate), 0) AS Out_Diff 
    FROM 
     CTE 
) A 

Ergebnis

UserId LogDate      Direction In_Diff  Out_Diff 
7034 2016-08-08 08:20:59.000  in  
7034 2016-08-08 08:21:04.000  in  
7034 2016-08-08 08:21:14.000  in  
7034 2016-08-08 08:21:26.000  out   00:00:12  
7034 2016-08-08 08:21:34.000  in      00:00:08 
7034 2016-08-08 09:35:26.000  out   01:13:52  
7034 2016-08-08 10:01:14.000  in      00:25:48 
7034 2016-08-08 12:35:17.000  out   02:34:03  
7034 2016-08-08 12:37:58.000  in      00:02:41 
7034 2016-08-08 13:29:13.000  out   00:51:15  
7034 2016-08-08 13:30:08.000  out    
7034 2016-08-08 13:30:13.000  out    
7034 2016-08-08 14:30:24.000  in      01:00:11 
7034 2016-08-08 17:30:24.000  out   03:00:00  
7034 2016-08-08 17:40:24.000  in      00:10:00 
7034 2016-08-08 22:15:38.000  out   04:35:14  
7034 2016-08-08 22:50:05.000  in      00:34:27 
7034 2016-08-09 01:20:05.000  out   02:30:00  
7034 2016-08-09 01:22:10.000  in      00:02:05 
7034 2016-08-09 04:50:15.000  out   03:28:05