如何在轮班附近的一天内获得第一个员工入口

时间:2015-05-21 19:17:08

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

我有一个 employee_attendance 表(SQL Server 2012),其中包含以下列:

  • 出勤率(身份)
  • EmployeeId
  • 时间戳(打卡或打卡)
  • AccessCode(I = IN,O = OUT)

以下是 SQL小提琴,其中包含一些示例数据:http://sqlfiddle.com/#!3/ba8a1/1

我知道这些员工可以在我们拥有的3个班次中的任何一天工作:

  1. 班次A(从07:00到15:00)
  2. 班次B(从15:00到23:00)
  3. 转换C(第二天23:00至次日07:00)
  4.   

    所以我需要的是知道每个员工在选定的一天(样本数据只有一天,并且已过滤只显示 IN 记录,所以只有 IN 访问公司)是Shift入口附近(低于或高于)的第一个Timestamp

    以下是应用正确脚本后SQL Fiddle数据应该是什么样子的图像:

    enter image description here

2 个答案:

答案 0 :(得分:1)

由于你有SQL Server 2012,你可以使用TimeFromParts和“mod 8”来减少工作......

select employeeId,
       accessCode,
       minDiff = MIN(ABS(DATEDIFF(TIMEFROMPARTS(DATEPART(HH,t.timestamp) % 8,
                                               (DATEPART(MI,t.timestamp),
                                               (DATEPART(S,t.timestamp),0,0),
                                  TIMEFROMPARTS(7,
                                               (DATEPART(MI,t.timestamp),
                                               (DATEPART(S,t.timestamp))
from table t
were t.timestamp is in a given daily range

所以,因为你的班次变化(7,15,23)都是“mod 8 = 7”我只是把时间戳“mod 8”的小时部分比作“7” - 这样我就不需要了运行查询三次。

答案 1 :(得分:0)

SQLFiddle(感谢您提供示例数据):http://sqlfiddle.com/#!3/ba8a1/7/0

查询:

declare @day datetime = '5-20-15' --not necessary, but included for more flexibility; you can just hardcode the date below if you want

SELECT *, '7:00:00 shift' as Shift
, abs(datediff(minute, timestamp, @day + '7:00:00')) as TimeDiff
into #temp
FROM employee_attendance
union all
SELECT *, '15:00:00 shift'
, abs(datediff(minute, timestamp, @day + '15:00:00'))
FROM employee_attendance
union all
SELECT *, '23:00:00 shift'
, abs(datediff(minute, timestamp, @day + '23:00:00'))
FROM employee_attendance

select * from (
  select *
  , row_number() over (partition by EmployeeID order by TimeDiff) as RowN
  from #temp
  ) a
where RowN = 1

说明:

  1. 为每个班次创建一个行,用于每个班次开始时间。
  2. 计算实际开始时间与列出的时钟输入时间之间的差异。取绝对值是因为原始请求正在寻找最接近的时钟输入,而不一定在转换开始之前。
  3. 使用row_number标识每个员工的行与班次开始时间的最短差异。
  4. 仅返回与班次开始时间最近的行。
  5. 正如其他人所指出的那样,这假设员工每天只有一个轮班,并且离班次最接近的时钟是有效的。对于每天单班制,可能更有意义的是提出替代标准 - 例如,查看绝对最早的时钟输入,或者在给定窗口内最早的时钟输入(比如6:30到7: 30,对于7:00班次),但这不是这个请求者要求的。