2015-05-21 11 views
5

Tôi có một employee_attendance bảng (SQL Server 2012) với các cột sau:Làm thế nào để có được lối vào đầu tiên nhân viên trong một ngày gần shift mình

  • AttendanceId (Identity)
  • EmployeeID
  • Timestamp (đục lỗ trong hoặc ngoài)
  • Mã truy cập (I = IN, O = OUT)

Đây là SQL Fiddle với một số dữ liệu mẫu: http://sqlfiddle.com/#!3/ba8a1/1

Tôi biết rằng những nhân viên có thể làm việc trên bất kỳ ngày nào trên bất kỳ của 3 ca chúng ta có:

  1. phím Shift A (Từ 07:00 đến 15:00)
  2. phím Shift B (Từ 15:00 đến 23:00)
  3. phím Shift C (Từ 23:00-07:00 ngày hôm sau)

Vì vậy, những gì tôi cần biết cho mỗi nhân viên trong một ngày đã chọn (dữ liệu mẫu chỉ có một ngày và đã được lọc để chỉ hiển thị IN hồ sơ, do đó chỉ IN truy cập vào công ty) là Timestamp đầu tiên đó là gần (dưới hoặc trên) lối vào Shift.

Dưới đây là hình ảnh của những gì dữ liệu SQL Fiddle nên trông giống như sau khi áp dụng kịch bản phải:

enter image description here

+0

yay cho câu đố sql với dữ liệu mẫu! <3 – Kritner

+2

Đối với nhân viên 116, dấu thời gian mà bạn chỉ định là đúng 45 phút trước khi bắt đầu ca làm việc trong khi dấu thời gian khác (15:25:43) chỉ cách 25 phút. Vì vậy, bạn không tìm kiếm gần nhất, chính xác? Điều gì sẽ xảy ra nếu 14:15:35 thực sự là 12:15:35? Nhân viên có thực sự sớm hoặc trễ 25 phút không? Dữ liệu có đủ sạch sẽ để nói sẽ luôn chỉ có một thay đổi cho mỗi nhân viên trong một ngày nhất định và chúng tôi luôn có thể sử dụng dấu thời gian sớm nếu nó tồn tại và nếu không sử dụng dấu thời gian trễ? –

+0

Làm cách nào để biết ai đó đang thay đổi ai? –

Trả lời

0

SQLFiddle (nhờ việc cung cấp dữ liệu mẫu): http://sqlfiddle.com/#!3/ba8a1/7/0

Query:

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 

Giải thích:

  1. Tạo hàng cho từng nhân viên, cho mỗi lần bắt đầu thay đổi.
  2. Tính chênh lệch giữa thời gian bắt đầu thực tế và thời gian đồng hồ được liệt kê. Lấy giá trị tuyệt đối vì yêu cầu ban đầu đang tìm kiếm đồng hồ gần nhất, không nhất thiết trước khi bắt đầu thay đổi.
  3. Sử dụng row_number để xác định hàng cho mỗi nhân viên có chênh lệch ngắn nhất với thời gian bắt đầu thay đổi.
  4. Chỉ trả lại hàng gần nhất cho thời gian bắt đầu thay đổi.

Như những người khác đã lưu ý, điều này giả định rằng một nhân viên chỉ có một ca làm việc mỗi ngày và đồng hồ gần nhất với thời gian thay đổi là thời gian hợp lệ. Đối với một hệ thống thay đổi mỗi ngày, có thể có ý nghĩa hơn để đưa ra các tiêu chí thay thế - ví dụ: xem đồng hồ sớm nhất tuyệt đối hoặc đồng hồ đầu tiên trong cửa sổ cho trước (nói 6:30 đến 7: 30, cho sự thay đổi 7:00), nhưng đó không phải là những gì người yêu cầu này đã yêu cầu.

+0

Cảm ơn phản hồi @TabAlleman - Tôi đã thêm nhiều chi tiết hơn. – APH

1

Vì bạn có SQL Server 2012, bạn có thể sử dụng TimeFromParts và "mod 8" tất cả mọi thứ để giảm thiểu công việc ...

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 

Vì vậy, kể từ khi thay đổi sự thay đổi của bạn (7,15,23) là tất cả "mod 8 = 7" Tôi chỉ so sánh phần thời gian của dấu thời gian "mod 8" với "7" - theo cách đó tôi không cần phải chạy truy vấn ba lần.

+0

Tôi thích sự sang trọng của mod 8, tôi sẽ phải nhớ điều này trong lần tiếp theo tôi gặp phải một vấn đề tương tự. – chrlsuk

Các vấn đề liên quan