员工优先IN&最后OUT刷卡 - SQL Server 2012

时间:2016-09-21 11:59:30

标签: sql sql-server

我正在尝试在SQL Server 2012中创建一个查询来计算First IN和&之间的时差。公司中每位员工的最后一次刷卡(正常的白班和夜班)。下面是我查询的样本数据。

Create table #TempData  (EmpName nvarchar(50),EventDateTime DateTime, TrnName nvarchar(20),TrnCode int)

Insert Into #TempData Values
('User1','2015-08-04 09:10:53','Entrance','0'),
('User1','2015-08-04 10:43:52','Exit','1'),
('User1','2015-08-04 11:13:23','Entrance','0'),
('User1','2015-08-04 13:32:29','Exit','1'),
('User1','2015-08-05 09:46:19','Exit','1'),
('User1','2015-08-05 10:22:28','Entrance','0'),
('User1','2015-08-06 18:47:02','Exit','1'),
('User1','2015-08-06 19:29:02','Entrance','0'),
('User1','2015-08-06 21:05:26','Exit','1'),
('User1','2015-08-18 11:54:42','Entrance','0'),
('User1','2015-08-18 19:19:02','Exit','1'),
('User1','2015-08-18 20:15:01','Entrance','0'),
('User1','2015-08-18 20:57:49','Exit','1'),
('User1','2015-08-19 12:10:48','Entrance','0'),
('User1','2015-08-20 11:57:04','Entrance','0'),
('User1','2015-08-20 20:57:19','Exit','1'),
('User1','2015-08-24 18:14:26','Entrance','0'),
('User1','2015-08-25 02:28:31','Exit','1'),
('User1','2015-08-28 17:14:05','Entrance','0'),
('User1','2015-08-29 04:50:28','Exit','1'),
('User1','2015-09-03 17:40:53','Entrance','0'),
('User1','2015-09-04 02:42:57','Exit','1'),
('User1','2015-09-04 18:27:25','Entrance','0'),
('User1','2015-09-04 18:27:29','Entrance','0'),
('User1','2015-09-05 02:32:31','Exit','1'),
('User1','2015-09-07 10:58:24','Entrance','0'),
('User1','2015-09-07 14:04:54','Entrance','0'),
('User1','2015-09-07 17:55:52','Exit','1'),
('User1','2015-09-08 17:51:20','Entrance','0'),
('User1','2015-09-09 02:25:20','Exit','1')

以下是我正在使用的查询。

 ;with cte as
(
    select 
    ROW_NUMBER() over(order by EmpName,EventDateTime) rn,
    EmpName, EventDateTime,
    cast(EventDateTime as date) EventDate,
    TrnName,TrnCode
from #TempData 
)
,ctee
as
(
select 
 Ent.rn as Ent_Rn, Ent.EmpName as Ent_EmpName, 
 Ent.EventDate as Ent_EventDate, Ent.EventDateTime as Ent_EventDateTime, 
 Ex.rn as Ex_Rn,EX.EmpName as Ex_EmpName,
 Ex.EventDate as Ex_EventDate, Ex.EventDateTime as Ex_EventDateTime
from
(
select 
    * 
from cte 
where TrnName = 'Entrance'
) as Ent
full join
(
select 
    * 
from cte 
where TrnName = 'Exit'
) as Ex
on Ent.rn+1 = Ex.rn and Ent.EmpName = Ex.EmpName 
)
,cteee
as
(
select 
case when Ent_EmpName is null then  Ex_EmpName  
     else Ent_EmpName
end as EmpName, 
Ent_EventDateTime as LoginTime, 
case 
    when DATEDIFF(hour, cast(Ent_EventDateTime as datetime),   cast(Ex_EventDateTime as datetime))>14 then null
    else Ex_EventDateTime 
end as LogoutTime
from ctee
)

select
*,
DATEDIFF(second,LoginTime,LogoutTime) As Seconds
,TIMEFROMPARTS(((DATEDIFF(second,LoginTime,LogoutTime))%(3600*24)/3600), 
(((DATEDIFF(second,LoginTime,LogoutTime))%(3600*24)%3600)/60), 
(((DATEDIFF(second,LoginTime,LogoutTime))%(3600*24)%3600)%60),0, 0) AS   WorkTime
from cteee order by EmpName, LoginTime

以下是我从上述查询中获得的当前结果。 enter image description here

然而,这是不正确的,因为这反映了每个IN&之间的实际时间。 OUT并为任何错过的IN / OUT输入NULL。但要求是为员工提供第一个IN和最后一个OUT(正常和夜班时间),无论多个IN& OUT IN& 1st之间的OUT最后OUT。但是,如果缺少任何IN或OUT或任何IN和OUT之间的时间差超过14小时,则将其标记为NULL。 以下是预期结果。

enter image description here

添加更多数据和结果反映结果不正确,因此需要修改NEER提供的查询。

数据:

 ('User1','2015-07-20 11:07:29','Entrance','0'),
 ('User1','2015-07-20 11:08:09','Exit','1'),
 ('User1','2015-07-20 21:13:27','Exit','1'),
 ('User1','2015-07-21 12:07:03','Entrance','0'),
 ('User1','2015-07-21 21:04:02','Exit','1'),
 ('User1','2015-07-22 11:48:06','Entrance','0'),
 ('User1','2015-07-22 13:37:15','Exit','1'),
 ('User1','2015-07-22 13:57:58','Entrance','0'),
 ('User1','2015-07-22 20:59:22','Exit','1'),
 ('User1','2015-07-23 12:38:41','Entrance','0'),
 ('User1','2015-07-23 17:33:43','Exit','1'),
 ('User1','2015-07-23 18:09:13','Entrance','0'),
 ('User1','2015-07-23 21:03:13','Exit','1'),
 ('User1','2015-07-24 11:51:03','Entrance','0'),
 ('User1','2015-07-24 14:19:41','Exit','1'),
 ('User1','2015-07-24 14:36:55','Entrance','0'),
 ('User1','2015-07-24 20:51:06','Exit','1'),
 ('User1','2015-07-27 12:10:54','Entrance','0'),
 ('User1','2015-07-27 17:45:36','Exit','1'),
 ('User1','2015-07-27 18:36:24','Entrance','0'),
 ('User1','2015-07-27 19:16:21','Exit','1'),
 ('User1','2015-07-27 20:01:12','Entrance','0'),
 ('User1','2015-07-27 21:04:47','Exit','1'),
 ('User1','2015-07-28 11:24:09','Entrance','0'),
 ('User1','2015-07-28 21:05:32','Exit','1'),
 ('User1','2015-07-29 12:03:09','Entrance','0'),
 ('User1','2015-07-29 18:36:07','Exit','1'),
 ('User1','2015-07-29 19:25:16','Entrance','0'),
 ('User1','2015-07-29 21:00:28','Exit','1'),
 ('User1','2015-07-30 11:58:43','Entrance','0'),
 ('User1','2015-07-30 13:09:18','Exit','1'),
 ('User1','2015-07-30 13:25:02','Entrance','0'),
 ('User1','2015-07-30 21:00:20','Exit','1'),
 ('User1','2015-07-31 12:11:36','Entrance','0'),
 ('User1','2015-07-31 19:46:47','Exit','1'),
 ('User1','2015-07-31 20:44:27','Entrance','0'),
 ('User1','2015-07-31 21:34:07','Exit','1')

目前的结果: enter image description here 这是我获得新数据的输出。当我在查询中直接使用表时,会出现相同的结果。

3 个答案:

答案 0 :(得分:1)

尝试如下:

declare @TempData Table (EmpName nvarchar(50),EventDateTime DateTime, TrnName nvarchar(20),TrnCode int)

Insert Into @TempData Values
('User1','2015-08-04 09:10:53','Entrance','0'),
('User1','2015-08-04 10:43:52','Exit','1'),
('User1','2015-08-04 11:13:23','Entrance','0'),
('User1','2015-08-04 13:32:29','Exit','1'),
('User1','2015-08-05 09:46:19','Exit','1'),
('User1','2015-08-05 10:22:28','Entrance','0'),
('User1','2015-08-06 18:47:02','Exit','1'),
('User1','2015-08-06 19:29:02','Entrance','0'),
('User1','2015-08-06 21:05:26','Exit','1'),
('User1','2015-08-18 11:54:42','Entrance','0'),
('User1','2015-08-18 19:19:02','Exit','1'),
('User1','2015-08-18 20:15:01','Entrance','0'),
('User1','2015-08-18 20:57:49','Exit','1'),
('User1','2015-08-19 12:10:48','Entrance','0'),
('User1','2015-08-20 11:57:04','Entrance','0'),
('User1','2015-08-20 20:57:19','Exit','1'),
('User1','2015-08-24 18:14:26','Entrance','0'),
('User1','2015-08-25 02:28:31','Exit','1'),
('User1','2015-08-28 17:14:05','Entrance','0'),
('User1','2015-08-29 04:50:28','Exit','1'),
('User1','2015-09-03 17:40:53','Entrance','0'),
('User1','2015-09-04 02:42:57','Exit','1'),
('User1','2015-09-04 18:27:25','Entrance','0'),
('User1','2015-09-04 18:27:29','Entrance','0'),
('User1','2015-09-05 02:32:31','Exit','1'),
('User1','2015-09-07 10:58:24','Entrance','0'),
('User1','2015-09-07 14:04:54','Entrance','0'),
('User1','2015-09-07 17:55:52','Exit','1'),
('User1','2015-09-08 17:51:20','Entrance','0'),
('User1','2015-09-09 02:25:20','Exit','1'),
('B','2016-06-22 17:27:00','Exit','1'), 
('B','2016-06-22 17:42:01','Entrance','0'), 
('B','2016-06-22 21:27:59','Exit','1'), 
('B','2016-06-22 21:45:47','Exit','1'), 
('B','2016-06-22 21:56:15','Entrance','0'), 
('B','2016-06-23 00:42:44','Exit','1'), 
('B','2016-06-23 01:03:06','Entrance','0'), 
('B','2016-06-23 02:47:18','Exit','1')


;WITH CTE1
AS
(
    SELECT
        *,
        ROW_NUMBER() OVER (ORDER BY CAST(T.EventDateTime AS DATE)) AS RowId
    FROM
        @TempData T
), CTE2
AS
(
        SELECT 
            A.EmpName,
            A.EventDateTime,
            A.TrnName,
            A.TrnCode,
            DENSE_RANK() OVER (ORDER BY MIN(B.RowId)) [Group]
        FROM 
            CTE1 A CROSS JOIN CTE1 B
        WHERE 
            ABS(DATEDIFF(HOUR, A.EventDateTime, B.EventDateTime)) BETWEEN 0 AND 14 -- Here 
        GROUP BY 
                A.EmpName,
                A.EventDateTime,
                A.TrnName,
                A.TrnCode
), CTE3
AS
(
    SELECT
        T.EmpName,      
        MIN(IIF(T.TrnCode = 0, T.EventDateTime, NULL)) InDate,
        MAX(IIF(T.TrnCode = 1, T.EventDateTime, NULL)) OutDate
    FROM
        CTE2 T
    GROUP BY
        T.EmpName,
        T.[Group]
), FinalTable
AS
(
    SELECT
        T.EmpName ,
        T.InDate,
        IIF(T.InDate > T.OutDate, NULL, T.OutDate) AS OutDate
    FROM CTE3 T 

    UNION

    SELECT
        T.EmpName ,
        IIF(T.InDate > T.OutDate, NULL, T.InDate) AS InDate,
        T.OutDate AS OutDate
    FROM CTE3 T 
)


SELECT
    F.EmpName ,
    F.InDate ,
    F.OutDate,
    DATEDIFF(SECOND, F.InDate, F.OutDate) [Second],
    CONVERT(CHAR(8),DATEADD(SECOND,DATEDIFF(SECOND,F.InDate,F.OutDate),'1900-1-1'),8) WorkTime
FROM 
    FinalTable F

结果:

EmpName     InDate                      OutDate                     Second      WorkTime
----------- -----------------------     -----------------------     ----------- --------
User1       NULL                        2015-08-05 09:46:19.000     NULL        NULL
User1       2015-08-04 09:10:53.000     2015-08-04 13:32:29.000     15696       04:21:36
User1       2015-08-05 10:22:28.000     NULL                        NULL        NULL
User1       2015-08-06 19:29:02.000     2015-08-06 21:05:26.000     5784        01:36:24
User1       2015-08-18 11:54:42.000     2015-08-18 20:57:49.000     32587       09:03:07
User1       2015-08-19 12:10:48.000     NULL                        NULL        NULL
User1       2015-08-20 11:57:04.000     2015-08-20 20:57:19.000     32415       09:00:15
User1       2015-08-24 18:14:26.000     2015-08-25 02:28:31.000     29645       08:14:05
User1       2015-08-28 17:14:05.000     2015-08-29 04:50:28.000     41783       11:36:23
User1       2015-09-03 17:40:53.000     2015-09-04 02:42:57.000     32524       09:02:04
User1       2015-09-04 18:27:25.000     2015-09-05 02:32:31.000     29106       08:05:06
User1       2015-09-07 10:58:24.000     2015-09-07 17:55:52.000     25048       06:57:28
User1       2015-09-08 17:51:20.000     2015-09-09 02:25:20.000     30840       08:34:00
B           2016-06-22 17:42:01.000     2016-06-23 02:47:18.000     32717       09:05:17

答案 1 :(得分:0)

您可以使用以下步骤计算每位员工的登录,注销和工作时间 1.1st为原始表中的数据处理创建临时表 2.来自该临时表的查询 3.表示临时表

 Create table #Process_data (EmpName nvarchar(50),login_Time  DateTime,logout_Time DateTime)

go
insert into #process_data(EmpName,login_Time)
select EmpName,MIN(EventDateTime) as login_Time  from #TempData
where TrnCode =0
group by EmpName,CONVERT(date,EventDateTime)

go
update #process_data
set logout_Time=case when logout_Time is null
then ( SELECT 
MAX(EventDateTime)  FROM #TempData
where #TempData.EmpName= #process_data.EmpName
and CONVERT(date,#TempData.EventDateTime)=CONVERT(date,#process_data.login_Time)
 and EventDateTime>login_Time
 and TrnCode =1
  )
else logout_Time end 
 go

  select EmpName,login_Time,logout_time,  datediff(second,login_time,logout_time) as[second],datediff(second,login_time,logout_time)/3600.0 as workingTime
 from #process_data



             EmpName    login_Time              logout_time            second   workingTime
             User1      2015-08-04 09:10:53.000 2015-08-04 13:32:29.000 15696   4.360000
             User1      2015-08-05 10:22:28.000 NULL                     NULL   NULL
             User1      2015-08-06 19:29:02.000 2015-08-06 21:05:26.000  5784   1.606666
             User1      2015-08-18 11:54:42.000 2015-08-18 20:57:49.000 32587   9.051944
             User1      2015-08-19 12:10:48.000             NULL         NULL   NULL
             User1      2015-08-20 11:57:04.000 2015-08-20 20:57:19.000 32415   9.004166
             User1  2015-08-24 18:14:26.000                 NULL         NULL   NULL
             User1  2015-08-28 17:14:05.000                 NULL         NULL   NULL
             User1  2015-09-03 17:40:53.000                 NULL         NULL   NULL
             User1  2015-09-04 18:27:25.000                 NULL         NULL   NULL
             User1  2015-09-07 10:58:24.000 2015-09-07 17:55:52.000     25048   6.957777
             User1  2015-09-08 17:51:20.000                 NULL         NULL   NULL

答案 2 :(得分:0)

SELECT  FinalEntranceData.EmpName,FinalEntranceData.eventdatetime [LoginTime],FinalExitData.eventdatetime [LogoutTime],DATEDIFF(second,FinalEntranceData.eventdatetime,FinalExitData.eventdatetime) As Seconds FROM 
(
    SELECT  seqnumber,empName,eventdatetime FROM
    (
       SELECT ROW_NUMBER() OVER (PARTITION BY empName,CONVERT(VARCHAR(20),eventdatetime,112) ORDER BY eventdatetime)seqnumber,empname,eventdatetime FROM #TempData WHERE trnname ='Entrance'  
    ) EntranceData WHERE seqnumber=1
) FinalEntranceData
INNER JOIN
(
    SELECT  seqnumber,empName,eventdatetime  FROM 
    (
        SELECT  ROW_NUMBER() OVER (PARTITION BY empName,CONVERT(VARCHAR(20),eventdatetime,112)  ORDER BY eventdatetime DESC  )seqnumber, * FROM #TempData WHERE trnname ='Exit'
    )ExitData  WHERE seqnumber=1

)FinalExitData ON FinalEntranceData.empname =FinalExitData.empname AND CONVERT(VARCHAR(20),FinalEntranceData.eventdatetime,112) = CONVERT(VARCHAR(20),FinalExitData.eventdatetime,112)