选择不同班次的时间和超时

时间:2017-06-29 01:10:45

标签: sql sql-server sql-server-2014

我需要每天为每位员工找出时钟和时钟。它有2班,第一班从0830 - 2030开始,第二班是从2030 - 0830(第二天)。以下是我的样本记录,

 Time In                    Time Out             User
2017-06-16 07:30:00.000 2017-06-16 08:30:00.000 I0495
2017-06-16 08:30:00.000 2017-06-16 12:30:00.000 I0495
2017-06-16 13:00:00.000 2017-06-16 15:30:00.000 I0495
2017-06-16 15:30:00.000 2017-06-16 19:00:00.000 I0495

2017-06-16 20:30:00.000 2017-06-16 21:30:00.000 I0603
2017-06-16 21:30:00.000 2017-06-17 00:00:00.000 I0603
2017-06-17 00:00:00.000 2017-06-17 00:30:00.000 I0603
2017-06-17 01:30:00.000 2017-06-17 04:30:00.000 I0603
2017-06-17 05:30:00.000 2017-06-17 08:30:00.000 I0603

2017-06-17 07:30:00.000 2017-06-17 08:30:00.000 I0495
2017-06-17 08:30:00.000 2017-06-17 12:30:00.000 I0495
2017-06-17 13:00:00.000 2017-06-17 15:30:00.000 I0495
2017-06-17 15:30:00.000 2017-06-17 19:00:00.000 I0495

我尝试查询如下

Select min(tbl.timein), max(tbl.timeout), tbl.user form
(
Select timein, timeout, user from tbl where timein >= '2017-06-16 
07:00:00' and timeout <= '2017-06-16 20:30:00' 
union all
Select timein, timeout, user from tbl where timein >= '2017-06-16 
20:60:00' and timeout <= '2017-06-17 08:30:00'
)tbl
group by tb.user

我得到的结果低于预期的结果

2017-06-16 07:30:00.000 2017-06-17 08:30:00.000 I0495
2017-06-16 20:30:00.000 2017-06-17 08:30:00.000 I0603
2017-06-17 07:30:00.000 2017-06-18 08:30:00.000 I0495   

预期结果

2017-06-16 07:30:00.000 2017-06-16 19:00:00.000 I0495
2017-06-16 20:30:00.000 2017-06-17 08:30:00.000 I0603
2017-06-17 07:30:00.000 2017-06-17 19:00:00.000 I0495

知道如何做到这一点。感谢。

2 个答案:

答案 0 :(得分:0)

一种合理的解决方法,可以知道用户在超时和下一次超时之间可以进行的最大中断。假设它是<= 2小时,你可以通过获得先前超时与每个用户当前行的时间的差异来实现。然后使用运行总和基于此分配每天的组。

select usr,timein,timeout
,sum(case when diff <=120 then 0 else 1 end) over(partition by usr order by timein) as grp
from (select t.*
      ,datediff(minute,lag(timeout) over(partition by usr order by timein),timein) as diff
      from tbl t
     ) t

分配组后,每个用户和组只需要min timein和max超时。

select usr,min(timein),max(timeout)
from (select usr,timein,timeout
      ,sum(case when diff <=120 then 0 else 1 end) over(partition by usr order by timein) as grp
      from (select t.*
           ,datediff(minute,lag(timeout) over(partition by usr order by timein),timein) as diff
            from tbl t
           ) t
     ) t
group by usr,grp

答案 1 :(得分:0)

也许这可以帮助并给你一个想法。

来源:

            DECLARE @T TABLE
                (
                  TimeIn DATETIME ,
                  [TimeOut] DATETIME ,
                  [User] VARCHAR(50)
                )

            INSERT  INTO @T
                    ( TimeIn, TimeOut, [User] )
            VALUES  ( '2017-06-16 07:30:00.000', '2017-06-16 08:30:00.000', 'I0495' ),
                    ( '2017-06-16 08:30:00.000', '2017-06-16 12:30:00.000', 'I0495' ),
                    ( '2017-06-16 13:00:00.000', '2017-06-16 15:30:00.000', 'I0495' ),
                    ( '2017-06-16 15:30:00.000', '2017-06-16 19:00:00.000', 'I0495' ),
                    ( '2017-06-16 20:30:00.000', '2017-06-16 21:30:00.000', 'I0603' ),
                    ( '2017-06-16 21:30:00.000', '2017-06-17 00:00:00.000', 'I0603' ),
                    ( '2017-06-17 00:00:00.000', '2017-06-17 00:30:00.000', 'I0603' ),
                    ( '2017-06-17 01:30:00.000', '2017-06-17 04:30:00.000', 'I0603' ),
                    ( '2017-06-17 05:30:00.000', '2017-06-17 08:30:00.000', 'I0603' ),
                    ( '2017-06-17 07:30:00.000', '2017-06-17 08:30:00.000', 'I0495' ),
                    ( '2017-06-17 08:30:00.000', '2017-06-17 12:30:00.000', 'I0495' ),
                    ( '2017-06-17 13:00:00.000', '2017-06-17 15:30:00.000', 'I0495' ),
                    ( '2017-06-17 15:30:00.000', '2017-06-17 19:00:00.000', 'I0495' );

查询:

            IF ( OBJECT_ID('tempdb..#tmpTbl') IS NOT NULL )
                BEGIN
                    DROP TABLE #tmpTbl
                END
            CREATE TABLE #tmpTbl
                (
                  id INT IDENTITY(1, 1)
                         PRIMARY KEY ,
                  TimeIn DATETIME ,
                  [TimeOut] DATETIME ,
                  [User] VARCHAR(50) ,
                  flag INT ,
                  [lag] INT
                )

            INSERT  INTO #tmpTbl
                    ( TimeIn ,
                      TimeOut ,
                      [User] ,
                      flag ,
                      lag
                    )
                    SELECT  TimeIn ,
                            TimeOut ,
                            [User] ,
                            flag ,
                            LAG(flag) OVER ( ORDER BY ctr ) LAG
                    FROM    ( SELECT    * ,
                                        IIF(CAST(TimeIn AS TIME) BETWEEN '7:00' AND '8:30', 1, IIF(CAST(TimeIn AS TIME) >= '20:30', 1, 0)) flag ,
                                        ROW_NUMBER() OVER ( ORDER BY ( SELECT
                                                                          0
                                                                     ) ) ctr
                              FROM      @T
                            ) TT 

            DECLARE @Lastid INT
            SELECT TOP 1
                    @Lastid = id
            FROM    #tmpTbl
            ORDER BY id DESC

            UPDATE  #tmpTbl
            SET     flag = 2
            WHERE   id = @Lastid

            UPDATE  #tmpTbl
            SET     flag = 0
            WHERE   lag = 1

            UPDATE  #tmpTbl
            SET     flag = 2
            WHERE   id IN ( SELECT  previd
                            FROM    ( SELECT    flag ,
                                                LAG(flag) OVER ( ORDER BY ID ) lag ,
                                                LAG(id) OVER ( ORDER BY ID ) previd
                                      FROM      #tmpTbl
                                    ) T
                            WHERE   T.flag = 1
                                    AND T.lag = 0 );
            WITH    CTE
                      AS ( SELECT   * ,
                                    ROW_NUMBER() OVER ( ORDER BY id ) ctr
                           FROM     #tmpTbl
                           WHERE    flag = 1
                         ),
                    CTE1
                      AS ( SELECT   * ,
                                    ROW_NUMBER() OVER ( ORDER BY id ) ctr
                           FROM     #tmpTbl
                           WHERE    flag = 2
                         ),
                    CTE2
                      AS ( SELECT   cte.TimeIn ,
                                    cte1.TimeOut ,
                                    cte.[user]
                           FROM     cte
                                    JOIN cte1 ON CTE1.ctr = CTE.ctr
                         )
                SELECT  *
                FROM    CTE2

结果:

        TimeIn                  TimeOut                 user
        ----------------------- ----------------------- -------
        2017-06-16 07:30:00.000 2017-06-16 19:00:00.000 I0495
        2017-06-16 20:30:00.000 2017-06-17 08:30:00.000 I0603
        2017-06-17 07:30:00.000 2017-06-17 19:00:00.000 I0495

        (3 row(s) affected)