计算员工的持续时间和外出时间

时间:2016-08-08 07:49:30

标签: sql sql-server sql-server-2012

我有一个名为DeviceLogs_8_2016的表格,其中存储了员工的及时和出时记录的所有记录。

表名每月更改一次。 例如:2016-09-01 0:00:00的记录将保存在名为DeviceLogs_9_2016

的表中

表包含所有员工的记录,如下所示, 但我只需要在指定日期单个UserId

+--------+---------------------+-----------+
| 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       |
+--------+---------------------+-----------+

全天只有一个UserID的样本数据如下所示

+--------+---------------------+-----------+
| 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       |
+--------+---------------------+-----------+

考虑当天的出勤时间从2016-08-08 05:00:00开始,到2016-08-09 05:00:00结束。

我想计算当天员工的总持续时间和总出时间。如果In或Out连续出现,那么我们只能考虑In之前的最后一个In和In之前的First Out。

我希望结果像

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

我已在excel表中计算出指定样本数据的计算结果。

╔═════════╦════════╦═════════════════════╦═══════════╦══════════╦══════════╦══════════════════╗
║ 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 ║                  ║
╚═════════╩════════╩═════════════════════╩═══════════╩══════════╩══════════╩══════════════════╝

3 个答案:

答案 0 :(得分:2)

试试这个

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

结果

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    

答案 1 :(得分:1)

此查询使用LAG()函数(更快)给出预期结果:

;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

结果:

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

答案 2 :(得分:-1)

items.RemoveAll(item => item.arret = arretName &&  
                        item.ligneSens == ligneSensName);