员工先进先出刷卡-SQL server 2012

员工先进先出刷卡-SQL server 2012,sql,sql-server,Sql,Sql Server,我正在尝试在SQL Server 2012中创建一个查询,以计算每个员工在公司正常白班和夜班时的先入和后出刷卡时间差。下面是我用于查询的示例数据 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','

我正在尝试在SQL Server 2012中创建一个查询,以计算每个员工在公司正常白班和夜班时的先入和后出刷卡时间差。下面是我用于查询的示例数据

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
下面是我从上述查询中得到的当前结果。

但是,这是不正确的,因为这反映了每次输入和输出之间的实际时间,以及任何遗漏的输入/输出的置零时间。但是,要求员工在正常和夜班的时间安排上做到先入后出,而不考虑先入后出之间的多次入/出。但是,如果缺少任何输入或输出,或者任何输入和输出之间的时间差超过14小时,则将其标记为空。 以下是预期结果

添加更多数据并重新选择结果,但结果不正确,因此需要修改NEER提供的查询

数据:

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

您可以使用以下步骤来计算每个员工的登录、注销和工作时间
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')
1.1从原始表为数据处理创建临时表 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
请尝试以下操作:

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

恐怕我还是有点不知所措,你能发布你希望最终输出的样子吗?如果一行中有多个出口或入口呢?@JohnBustos我已经在查询中添加了结果。@gofr1我有多个出口/入口的数据。因此,如果任何入口都有出口,我们应该忽略任何部分刷卡,因为我们是先入后出的。但是,如果每天只有一次刷卡,无论是进入还是退出,则分别将LoginTime或LogonUttime标记为空。我希望这能回答您的问题。由于我无法理解这些语句,请您根据MS SQL server修改此查询,并请共享查询结果。我已根据MS SQL server编辑了我的代码。让我知道它工作很抱歉,但查询不起作用,因为我可以看到很多空值,这是不正确的,因为我可以使用我的查询查看一些数据。查询看起来不错,但它失败了。下面是我得到的结果。A 2015-08-05 10:22:28.000 2015-08-05 09:46:19.000-2169 A 2015-08-25 17:35:25.000 2015-08-25 02:28:31.000-54414时间不能为负。注销时间应始终大于登录时间。数据库2015-08-05 10:22:28中的记录为登录时间,2015-08-05 09:46:19。是某一天的退出时间。所以我认为存在数据问题。不,实际上,用户没有进行刷卡,而是在当天第一次刷卡时进行了刷卡,后来又进行了刷卡,导致了问题。我正在寻找一个查询,它可以处理这样的条件,并标记LoginTime为NULL为OUT和LogoutTime为NULL为IN。非常感谢。它是有效的,我目前正在测试这个脚本,测试超过100000条记录,并希望在不超过30分钟的时间内检索到所需的结果:查询没有为超过100000条记录的数据提供任何结果。请您优化您的查询以便在SQL 2012中快速运行好吗?@ankurjain您可以尝试每月一次吗?虽然有效,但我可以在CTE2中发现一些问题,因为查询的CT1交叉连接的数据反映不正确,请您帮助解决该问题。请显示示例数据。
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