Sql 如何计算用户在工作上花费的加班时间

Sql 如何计算用户在工作上花费的加班时间,sql,sql-server,datetime,date-arithmetic,Sql,Sql Server,Datetime,Date Arithmetic,我有两个SQL Server表employeeempid、empname和employee_movementsempid、MoveDatetime,我按日期时间存储来自指纹的员工操作,我想计算每个员工从下午3:30到第二天早上6:00的下班时间 所以如果我有这些数据 | EmpID | MoveDateTime | |-------|--------------------| | 1 | 01.01.2020 3:30pm | | 1 | 01.01.2020 5:

我有两个SQL Server表employeeempid、empname和employee_movementsempid、MoveDatetime,我按日期时间存储来自指纹的员工操作,我想计算每个员工从下午3:30到第二天早上6:00的下班时间

所以如果我有这些数据

| EmpID | MoveDateTime | |-------|--------------------| | 1 | 01.01.2020 3:30pm | | 1 | 01.01.2020 5:30pm | | 1 | 01.01.2020 11:00pm | | 1 | 02.01.2020 02:30am | | 2 | 01.01.2020 4:00am | | 2 | 01.01.2020 10:15am | | 1 | 02.01.2020 4:00pm | | 1 | 02.01.2020 5:00pm | 我应该得到这个结果

| EmpID | Entrance | Departure | Actual_hours | |-------|--------------------|--------------------|--------------| | 1 | 01.01.2020 3:30PM | 01.01.2020 5:30PM | 2.00 | | 1 | 01.01.2020 11:00PM | 02.01.2020 2:30Am | 3.5 | | 2 | 01.01.2020 4:00AM | 01.01.2020 10:15PM | 7.25 | | 1 | 02.01.2020 04:00am | 02.01.2020 5:00am | 01.00 | 我试过这个密码

with cte as 
(
  SELECT *, ROW_NUMBER() OVER (PARTITION BY [EmpID], cast ([MoveDateTime] as Date) 
                               ORDER BY [MoveDateTime]) as rn
  FROM employee_movements t1 
)  
SELECT c1.EmpID, c1.rn,c2.rn,
       cast (c1.MoveDateTime as Date) as the_day,c1.MoveDateTime as enterance,c2.MoveDateTime as departure, cast (sum (DATEDIFF (S, c1.MoveDateTime, c2.MoveDateTime)/3600.00) as decimal(18,2)) as Actual_Hours
FROM cte c1
left JOIN cte c2
  ON 
c1.rn = c2.rn -1 AND 
c1.EmpID = c2.EmpID and c1.rn % 2 <> 0 
and (cast (c1.MoveDateTime as Date)=cast (c2.MoveDateTime as Date) ) or (c2.rn=1 and cast(dateadd(day,1,c1.MoveDateTime) as date)= cast(c2.MoveDateTime as Date) and (cast(c2.MoveDateTime as time) between '00:00:00' and '06:00:00')) 
AND c2.rn % 2 = 0
 where c2.rn is not null
GROUP BY c1.EmpID,c1.rn,c2.rn,
         cast (c1.MoveDateTime as Date) ,c1.MoveDateTime,c2.MoveDateTime
我从中了解到每个员工的进出和工作时间,但按一天划分的问题不会返回第二个案例,因为员工仍在工作,第二天就离开了


感谢您的帮助。

首先,您可以使用窗口函数交错行以生成输入/输出对:

select *
from (
    select empid, movedatetime as dt_in,
            lead(movedatetime) over(partition by empid order by movedatetime) as dt_out,
            row_number() over(partition by empid order by movedatetime) rn
        from employee_movements 
) t
where rn % 2 = 1
然后我们需要计算每个日期范围的加班时间。SQL Server在日期算法方面不是很好;如果您没有太多的行同时进行,最简单的方法可能是暴力:枚举两个日期之间的所有分钟数,只计算不属于工作时间的分钟数

因此:

:


请以表格形式提供样本数据和预期结果。加班时间从下午3:30开始,到第二天早上6:00结束。我想按天计算员工每次指纹操作之间的所有时间。谢谢GMB,干得好,但有一点遗漏了,那就是2020-10-13和2020-10-21中的dt_和dt_out,跨越了不止一天,但我只想计算从第一天15:30开始到第二天6:00(最大值)的运动的加班时间,并排除这两天中dt_out为空的奇怪动作interval@hussein.nagdy例如我不知道你在说什么。您所引用的数据不是示例数据的一部分,是吗?事实上,它不在示例数据中,但在我的数据库中,它与me@hussein.nagdy:这是我的观点。。。此查询适用于您提供的示例数据。如果您有一个不同的用例,那么您可能想问一个新问题,提供适当的样本数据和期望的结果。
with 
    data as (
        select empid, movedatetime as dt_in,
            lead(movedatetime) over(partition by empid order by movedatetime) as dt_out,
            row_number() over(partition by empid order by movedatetime) rn
        from employee_movements 
    ),
    cte as (
        select empid, dt_in, dt_out, dt_in as dt 
        from data 
        where rn % 2 = 1
        union all
        select empid, dt_in, dt_out, dateadd(minute, 1, dt) 
        from cte 
        where dateadd(minute, 1, dt) < dt_out
    )
select empid, dt_in, dt_out, 
    sum(
        case when convert(time, dt) >= '06:00:00' and convert(time, dt) < '15:30:00' 
        then 0 
        else 1 
    end) ot_minutes
from cte
group by empid, dt_in, dt_out
order by empid, dt_in
option (maxrecursion 0) 
empid | dt_in | dt_out | ot_minutes ----: | :---------------------- | :---------------------- | ---------: 1 | 2020-01-01 15:30:00.000 | 2020-01-01 17:30:00.000 | 120 1 | 2020-01-01 23:00:00.000 | 2020-01-02 02:30:00.000 | 210 1 | 2020-01-02 16:00:00.000 | 2020-01-02 17:00:00.000 | 60 2 | 2020-01-01 04:00:00.000 | 2020-01-01 22:15:00.000 | 525