如何计算SQL Server中的登录和注销时间

时间:2018-02-24 11:12:25

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

我对SQL Server有疑问:如何根据以下条件计算登录和注销时间?

  1. 同一名员工可能在同一天多班。注销和登录时间差异超过5小时,然后考虑为该员工的下一班次。

    登录和退出时间超过5小时或更短时间,然后仅考虑该员工的相同班次

  2. OnFloor时间花费了多少时间:sum(login time - logout time)

  3. OffFloor时间他花了多少时间:sum(logout time - login time)
  4. 示例:emp:101是登录时间:2018-02-06 16:03:08.000,退出时间为:2018-02-06 22:01:40.000则总时间为:5小时:38分钟:32秒

    CREATE TABLE [dbo].[empstafflogindetails]
    (
        [Emp ID] [float] NULL,
        [Area Of Access] [nvarchar](255) NULL,
        [Time] [datetime] NULL
    ) ON [PRIMARY]
    GO
    
    INSERT [dbo].[empstafflogindetails] ([Emp ID], [Area Of Access], [Time]) 
    VALUES (1, N' IN', CAST(N'2017-08-02T09:00:00.000' AS DateTime)),
           (1, N' OUT', CAST(N'2017-08-02T10:30:00.000' AS DateTime)), 
           (1, N' IN', CAST(N'2017-08-03T09:30:00.000' AS DateTime)),
           (1, N' OUT', CAST(N'2017-08-03T12:30:00.000' AS DateTime)), 
           (1, N' IN', CAST(N'2017-08-03T12:40:00.000' AS DateTime)),
           (1, N' OUT', CAST(N'2017-08-03T17:10:00.000' AS DateTime)),
           (1, N' IN', CAST(N'2017-08-03T06:30:00.000' AS DateTime)),
           (1, N' OUT', CAST(N'2017-08-03T08:30:00.000' AS DateTime)),
           (1, N' IN', CAST(N'2017-08-05T23:30:00.000' AS DateTime)),
           (1, N' OUT', CAST(N'2017-08-06T01:55:00.000' AS DateTime)),
           (1, N' IN', CAST(N'2017-08-06T02:15:00.000' AS DateTime)),
           (1, N' OUT', CAST(N'2017-08-06T06:10:00.000' AS DateTime)),
           (1, N' IN', CAST(N'2017-08-02T11:00:00.000' AS DateTime)),
           (1, N' OUT', CAST(N'2017-08-02T12:00:00.000' AS DateTime)),
           (1, N' IN', CAST(N'2017-08-02T13:00:00.000' AS DateTime)),
           (1, N' IN', CAST(N'2017-08-06T14:01:00.000' AS DateTime)),
           (1, N' OUT', CAST(N'2017-08-06T15:01:00.000' AS DateTime)),
           (1, N' IN', CAST(N'2017-08-06T15:20:00.000' AS DateTime)),
           (1, N' OUT', CAST(N'2017-08-06T20:01:00.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-05T16:23:49.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-05T16:26:01.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-05T15:20:07.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-05T16:00:07.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-05T16:02:02.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-05T22:41:40.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-05T22:56:33.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-05T22:58:28.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-05T22:58:32.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-05T23:00:28.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-05T21:47:38.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-05T23:28:33.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-06T16:03:08.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-06T22:01:40.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-06T22:42:15.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-07T01:32:08.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-07T00:33:19.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-07T00:33:39.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-07T14:57:57.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-07T22:34:51.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-07T23:05:13.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-07T23:19:57.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-07T23:24:07.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-07T23:31:32.000' AS DateTime)),
           (101, N' IN', CAST(N'2018-02-07T23:34:12.000' AS DateTime)),
           (101, N' OUT', CAST(N'2018-02-07T23:34:36.000' AS DateTime))
    GO
    

    根据以上数据,我想要输出如下:

    ShiftDate   |ShitStartTime                  |ShiftEndTime               |Total_Time |OnFloor    |OffFloor   |Emp Id
    2017-08-02  |2017-08-02 09:00:00.000        |2017-08-02 12:00:00.000    |04:00:00   |02:30:00   |01:30:00   |1
    2017-08-03  |2017-08-03 06:30:00.000        |2017-08-03 17:10:00.000    |10:40:00   |09:30:00   |01:10:00   |1
    2017-08-05  |2017-08-05 23:30:00.000        |2017-08-06 06:10:00.000    |06:40:00   |06:20:00   |00:20:00   |1
    2017-08-06  |2017-08-06 14:01:00.000        |2017-08-06 20:01:00.000    |06:00:00   |05:41:00   |00:19:00   |1
    2018-02-05  |2018-02-05 15:20:07.000        |2018-02-05 23:28:33.000    |08:08:26   |07:06:26   |01:02:00   |101
    2018-02-06  |2018-02-06 16:03:08.000        |2018-02-07 01:32:08.000    |09:29:00   |08:20:00   |01:09:00   |101
    2018-02-07  |2018-02-07 14:57:57.000        |2018-02-07 23:34:36.000    |08:36:39   |07:59:27   |00:37:12   |101
    

    我试过如下:

    select
        cast(ShitStartTime as date) ShiftDate, ShitStartTime, ShiftEndTime
        , concat(right(concat('0', tTime / 60 / 60 % 24), 2), ':', right(concat('0',tTime/ 60 % 60), 2)
        ,':',right(concat('0',tTime % 60), 2)) Total_Time
        ,concat(right(concat('0', onF / 60 / 60 % 24), 2), ':', right(concat('0',onF/ 60 % 60), 2)
        ,':',right(concat('0',onF % 60), 2))OnFloor
        ,
        concat(right(concat('0', offF / 60 / 60 % 24), 2), ':', right(concat('0',offF/ 60 % 60), 2)
        ,':',right(concat('0',offF % 60), 2))OffFloor, [Emp Id]
    from (
        select [Emp Id], isnull( min( case when ltrim( rtrim( [Area Of Access]))='in' then Time end  ) ,'1900-01-01')ShitStartTime ,
    isnull( max( case when ltrim(rtrim([Area Of Access]))='out'then Time end  ) ,'1900-01-01')ShiftEndTime,
    sum(iif(ltrim(rtrim([Area Of Access]))='in', diff, 0)) onF
    ,sum(iif(ltrim(rtrim([Area Of Access]))='out', diff, 0)) offF
    , sum(diff) tTime
     from (
            select *, datediff(SECOND, Time, lead(Time) over (partition by [Emp Id], group_ order by Time)) diff
    
            from (
                select
                    *, sum(gr) over (partition by [Emp Id] order by Time rows unbounded preceding) group_
                from (
                    select 
                        *, iif(datediff(hh, lag(Time) over (partition by [Emp Id] order by Time), Time) <= 5, 0, 1) gr
                    from 
                        empstafflogindetails
                        ) t
            ) t
        ) t
        group by [Emp Id], group_
    ) t order by [Emp ID],ShiftDate
    

    但是这个查询没有返回预期的结果。你能告诉我如何在SQL Server中编写查询来实现这个任务吗?

1 个答案:

答案 0 :(得分:0)

检查此查询

select
    ShiftDate, ShitStartTime, ShiftEndTime
    , Total_Time = right(concat('0', Total_Time / 3600), 2) + ':' + right(concat('0', Total_Time % 3600 / 60), 2) + ':' + right(concat('0', Total_Time % 60), 2)
    , OnFloor = right(concat('0', OnFloor / 3600), 2) + ':' + right(concat('0', OnFloor % 3600 / 60), 2) + ':' + right(concat('0', OnFloor % 60), 2)
    , OffFloor = right(concat('0', OffFloor / 3600), 2) + ':' + right(concat('0', OffFloor % 3600 / 60), 2) + ':' + right(concat('0', OffFloor % 60), 2)
    , [Emp ID]
from (
    select
        [Emp ID], ShiftDate = cast(min(Time) as date)
        , ShitStartTime = min(Time)
        , ShiftEndTime = max(Time)
        , Total_Time = sum(ss)
        , OnFloor = sum(iif(rtrim(ltrim([Area Of Access])) = 'In', ss, 0))
        , OffFloor = sum(iif(rtrim(ltrim([Area Of Access])) = 'Out', ss, 0))
    from (
        select
            *, ss = datediff(ss, Time, lead(Time) over (partition by [Emp ID], grp order by Time))
        from (
            select
                *, grp = sum(diff) over (partition by [Emp ID] order by Time)
            from (
                select
                    *, diff = iif(datediff(mi, lag(Time) over (partition by [Emp ID] order by Time), Time) > 300 and [Area Of Access] = 'IN', 1, 0)
                from
                    [empstafflogindetails]
            ) t
        ) t
    ) t
    group by [Emp ID], grp
) t

输出

ShiftDate   ShitStartTime             ShiftEndTime              Total_Time    OnFloor     OffFloor  [Emp ID]
-------------------------------------------------------------------------------------------------------------------------
2017-08-02  2017-08-02 09:00:00.000   2017-08-02 13:00:00.000   04:00:00      02:30:00    01:30:00  1
2017-08-03  2017-08-03 06:30:00.000   2017-08-03 17:10:00.000   10:40:00      09:30:00    01:10:00  1
2017-08-05  2017-08-05 23:30:00.000   2017-08-06 06:10:00.000   06:40:00      06:20:00    00:20:00  1
2017-08-06  2017-08-06 14:01:00.000   2017-08-06 20:01:00.000   06:00:00      05:41:00    00:19:00  1
2018-02-05  2018-02-05 15:20:07.000   2018-02-05 23:28:33.000   08:08:26      07:06:26    01:02:00  101
2018-02-06  2018-02-06 16:03:08.000   2018-02-07 01:32:08.000   09:29:00      08:48:05    00:40:55  101
2018-02-07  2018-02-07 14:57:57.000   2018-02-07 23:34:36.000   08:36:39      07:59:27    00:37:12  101