Đầu tiên, tốt hơn là đăng câu hỏi này từ câu hỏi khác của bạn. Lý do bạn nhận được nhiều hồ sơ là khả năng một người theo dõi ra vào nhiều lần trong cùng một ngày dựa trên ca làm việc của họ. Bây giờ, làm thế nào để giải quyết điều này.
Trong MySQL, bạn có thể khai báo và gán biến nội tuyến bằng cách sử dụng các biến "@" như một phần của mệnh đề FROM select. Những gì tôi đang bắt đầu là một phép nối đơn giản từ ngày làm việc đến bàn giao ca (và tôi nghĩ bây giờ tôi đã hiểu điều này), với một số @variables.
Đối với mỗi người, tham gia vào ca làm việc, tôi tính toán trước khi xảy ra giữa ca, chẳng hạn như cùng ngày so với ngày hôm sau. Ngoài ra, begin2 và end2 dường như là những ngoại lệ cho khả năng xung nhịp vào so với thời gian chờ. Ví dụ:Người 1 đang làm việc trong ca 1. Ca 1 được xác định cho bất kỳ ngày làm việc nhất định nào là
shiftcode shiftbegin2 shiftbegin shiftmid shiftend shiftend2
1 04:00:00 08:00:00 12:00:00 17:30:00 21:30:00
Vì vậy, tôi giải thích điều này như thể tôi làm việc vào ngày 28 tháng 6, Ca 1,
June 28 @ 4am Earliest allowed clock-in time
June 28 @ 8am Actual beginning of shift
June 28 @ 12pm (afternoon) is the middle of the work day
June 28 @ 5:30pm is the end of the work day
June 28 @ 9:30pm is the max expected clock-out recognized for the shift
Tương tự, đối với ca 2 sẽ kéo dài cả đêm
shiftcode shiftbegin2 shiftbegin shiftmid shiftend shiftend2
2 12:00:00 17:30:00 21:00:00 05:30:00 09:30:00
June 28 @ 12pm (afternoon) Earliest allowed clock-in time
June 28 @ 5:30pm Actual beginning of shift
June 28 @ 9pm is the middle of the shift
June 29 @ 5:30am (day roll-over) is the end of the work day
June 29 @ 9:30am (day roll-over) is the max expected clock-out for the shift
Vì vậy, nếu tất cả đều đúng, truy vấn bên trong của tôi đang xác định trước tất cả các phạm vi này cho mỗi người, vì vậy tôi sẽ chỉ có 1 bản ghi cho mỗi người mỗi ngày làm việc bất kể có bao nhiêu lần quét qua bên dưới.
select
wd.wdpercode,
wd.wdshift,
wd.wddate,
s.shiftbegin,
s.shiftend,
s.shiftbegin2,
s.shiftmid,
s.shiftend2,
@midDay := if( s.shiftbegin < s.shiftmid, wd.wddate, date_add( wd.wddate, interval 1 day )) as NewMidDay,
@endDay := if( s.shiftbegin < s.shiftend, wd.wddate, date_add( wd.wddate, interval 1 day )) as NewEndDay,
cast( concat(wd.wddate, ' ', s.shiftbegin2 ) as DateTime ) as EarliestClockIn,
cast( concat(wd.wddate, ' ', s.shiftbegin ) as DateTime ) as BeginShift,
cast( concat(@midDay, ' ', s.shiftmid ) as DateTime ) as MidShift,
cast( concat( @endDay, ' ', s.shiftend ) as DateTime ) as EndShift,
cast( concat( @endDay, ' ', s.shiftend2 ) as DateTime ) as MaxClockOut
from
( select
@endDay := '',
@midDay := '' ) sqlvars,
tb_workday wd
join tb_shift s
on wd.wdshift = s.shiftcode
Tính toán nội tuyến của @midDay và @endDay nên tôi không phải lo lắng về việc tham gia vào bảng đồng hồ thời gian đã quét và tiếp tục thêm 1 ngày vào giữa tất cả những thứ khác đang được xem xét. Vì vậy, ở phần cuối của truy vấn này, tôi sẽ kết thúc với một cái gì đó như ... Lưu ý giữa người 1 ca bình thường và người 2 ca đêm, ngày kết thúc được tính toán cũng hiển thị cả ngày luân chuyển
wdpercode wdshift wddate shiftbegin shiftend shiftbegin2 shiftmid shiftend2 NewMidDay NewEndDay EarliestClockIn BeginShift MidShift EndShift MaxClockOut
000001 1 2010-10-10 08:00 17:30 04:00 12:00 21:30 2010-10-10 2010-10-10 2010-10-10 04:00 2010-10-10 08:00 2010-10-10 12:00 2010-10-10 17:30 2010-10-10 21:30:00
000001 1 2010-10-11 08:00 17:30 04:00 12:00 21:30 2010-10-11 2010-10-11 2010-10-11 04:00 2010-10-11 08:00 2010-10-11 12:00 2010-10-11 17:30 2010-10-11 21:30:00
000001 1 2010-10-12 08:00 17:30 04:00 12:00 21:30 2010-10-12 2010-10-12 2010-10-12 04:00 2010-10-12 08:00 2010-10-12 12:00 2010-10-12 17:30 2010-10-12 21:30:00
000001 1 2010-10-13 08:00 17:30 04:00 12:00 21:30 2010-10-13 2010-10-13 2010-10-13 04:00 2010-10-13 08:00 2010-10-13 12:00 2010-10-13 17:30 2010-10-13 21:30:00
000002 2 2010-10-10 17:30 05:30 12:00 21:00 09:30 2010-10-10 2010-10-11 2010-10-10 12:00 2010-10-10 17:30 2010-10-10 21:00 2010-10-11 05:30 2010-10-11 09:30:00
000002 2 2010-10-11 17:30 05:30 12:00 21:00 09:30 2010-10-11 2010-10-12 2010-10-11 12:00 2010-10-11 17:30 2010-10-11 21:00 2010-10-12 05:30 2010-10-12 09:30:00
000002 2 2010-10-12 17:30 05:30 12:00 21:00 09:30 2010-10-12 2010-10-13 2010-10-12 12:00 2010-10-12 17:30 2010-10-12 21:00 2010-10-13 05:30 2010-10-13 09:30:00
000002 2 2010-10-13 17:30 05:30 12:00 21:00 09:30 2010-10-13 2010-10-14 2010-10-13 12:00 2010-10-13 17:30 2010-10-13 21:00 2010-10-14 05:30 2010-10-14 09:30:00
Bạn có thể xóa các cột thừa khỏi truy vấn này, nhưng tôi đã bao gồm tất cả để bạn có thể xem / xác nhận các giá trị cần xem xét của mỗi hàng và ngày làm việc đã lên lịch. Danh sách viết tắt mà tôi vẫn cần là
select
wd.wdpercode,
@midDay := if( s.shiftbegin < s.shiftmid, wd.wddate, date_add( wd.wddate, interval 1 day )) as NewMidDay,
@endDay := if( s.shiftbegin < s.shiftend, wd.wddate, date_add( wd.wddate, interval 1 day )) as NewEndDay,
cast( concat(wd.wddate, ' ', s.shiftbegin2 ) as DateTime ) as EarliestClockIn,
cast( concat(wd.wddate, ' ', s.shiftbegin ) as DateTime ) as BeginShift,
cast( concat(@midDay, ' ', s.shiftmid ) as DateTime ) as MidShift,
cast( concat( @endDay, ' ', s.shiftend ) as DateTime ) as EndShift,
cast( concat( @endDay, ' ', s.shiftend2 ) as DateTime ) as MaxClockOut
Vì vậy, nếu điều trên là chính xác, bây giờ chúng ta phải lấy đồng hồ vào và ra cho mỗi người dựa trên phạm vi TỐI ĐA được tính toán từ truy vấn này CÓ THỂ nhiều hơn một bản ghi mỗi ngày
wdpercode EarliestClockIn MidShift MaxClockOut
000001 2010-10-10 04:00 2010-10-10 12:00 2010-10-10 21:30:00
000002 2010-10-10 12:00 2010-10-10 21:00 2010-10-11 09:30:00
Vì vậy, ở đây, tôi đang tham gia vào thời gian quét cho bất kỳ ngày nào trong đồng hồ sớm nhất trong và đồng hồ tối đa và sử dụng dịch chuyển giữa làm cơ sở để xác định xem họ đến muộn hay về sớm. Tôi đã thêm MIN () và MAX () bổ sung cho thời gian đến và đi của một người / ca cụ thể chỉ để xác nhận những gì bạn LÀM VÀ sẽ thấy.
Mục đích của MAX (IF ()) là để ghi lại trạng thái muộn / sớm CHỈ KHI chúng đã xảy ra. Vì nhóm theo từng ca làm việc, bản ghi đầu tiên (đồng hồ vào) có thể bị trễ và bạn muốn thời gian đó, nhưng bản ghi thứ hai cho hết giờ không áp dụng được qua thời gian giữa ca và do đó sẽ bị trống. Tương tự như vậy để phát hiện sớm việc rời ca làm việc.
select
perPerson.wdPerCode,
perPerson.BeginShift,
perPerson.EndShift,
min( TS.scScanTime ) as Arrival,
max( TS.scScanTime ) as Departure,
max( IF( TS.scScanTime > perPerson.BeginShift
AND TS.scScanTime <= perPerson.MidShift, TS.scScanTime, "" )) as LateArrival,
max( IF( TS.scScanTime > perPerson.MidShift
AND TS.scScanTime < perPerson.EndShift, TS.scScanTime, "" )) as EarlyDepart
from
( select
wd.wdpercode,
@midDay := if( s.shiftbegin < s.shiftmid, wd.wddate,
date_add( wd.wddate, interval 1 day )) as NewMidDay,
@endDay := if( s.shiftbegin < s.shiftend, wd.wddate,
date_add( wd.wddate, interval 1 day )) as NewEndDay,
cast( concat(wd.wddate, ' ', s.shiftbegin2 ) as DateTime ) as EarliestClockIn,
cast( concat(wd.wddate, ' ', s.shiftbegin ) as DateTime ) as BeginShift,
cast( concat(@midDay, ' ', s.shiftmid ) as DateTime ) as MidShift,
cast( concat( @endDay, ' ', s.shiftend ) as DateTime ) as EndShift,
cast( concat( @endDay, ' ', s.shiftend2 ) as DateTime ) as MaxClockOut
from
( select
@endDay := '',
@midDay := '' ) sqlvars,
tb_workday wd
join tb_shift s
on wd.wdshift = s.shiftcode ) perPerson
JOIN tb_scan TS
on perPerson.wdpercode = TS.scpercode
AND TS.scScanTime >= perPerson.EarliestClockIn
AND TS.scScanTime <= perPerson.MaxClockOut
group by
perPerson.wdPerCode,
perPerson.BeginShift;
Tôi đã tạo bảng và dữ liệu mẫu từ những gì bạn đã cung cấp (trong đó một số dữ liệu của bạn không khớp với ngày và phạm vi mẫu, vì vậy tôi đã điều chỉnh để làm như vậy).
CREATE TABLE `tb_scan` (
`scpercode` varchar(6) DEFAULT NULL,
`scscantime` datetime,
KEY `all` (`scyear`,`scmonth`,`scday`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
insert into tb_scan
( scpercode, scscantime )
values
( '000001', '2010-10-10 08:02:00' ),
( '000001', '2010-10-10 17:33:00' ),
( '000001', '2010-10-11 07:48:00' ),
( '000001', '2010-10-11 17:29:00' ),
( '000001', '2010-10-12 08:04:00' ),
( '000001', '2010-10-12 17:28:00' ),
( '000002', '2010-10-10 17:31:00' ),
( '000002', '2010-10-11 05:35:00' ),
( '000002', '2010-10-11 17:28:00' ),
( '000002', '2010-10-12 05:29:00' ),
( '000002', '2010-10-12 17:32:00' ),
( '000002', '2010-10-13 05:27:00' );
CREATE TABLE `tb_workday` (
`wdpercode` varchar(6) DEFAULT NULL,
`wdshift` varchar(1) DEFAULT NULL,
`wddate` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
insert into tb_workday
( wdpercode, wdshift, wddate )
values
( '000001', '1', '2010-10-10' ),
( '000001', '1', '2010-10-11' ),
( '000001', '1', '2010-10-12' ),
( '000001', '1', '2010-10-13' ),
( '000002', '2', '2010-10-10' ),
( '000002', '2', '2010-10-11' ),
( '000002', '2', '2010-10-12' ),
( '000002', '2', '2010-10-13' );
CREATE TABLE `tb_shift` (
`shiftcode` varchar(1) DEFAULT NULL,
`shiftbegin2` varchar(8) DEFAULT NULL,
`shiftbegin` varchar(8) DEFAULT NULL,
`shiftmid` varchar(8) DEFAULT NULL,
`shiftend` varchar(8) DEFAULT NULL,
`shiftend2` varchar(8) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
insert into tb_shift
( shiftcode, shiftbegin2, shiftbegin, shiftmid, shiftend, shiftend2 )
values
( '1', '04:00:00', '08:00:00', '12:00:00', '17:30:00', '21:30:00' ),
( '2', '12:00:00', '17:30:00', '21:00:00', '05:30:00', '09:30:00' );
Dữ liệu mẫu cho thấy mỗi người có 1:đến muộn, 2:khởi hành sớm, 3:đến muộn VÀ khởi hành sớm.
wdPerCode BeginShift EndShift Arrival Departure LateArrival EarlyDepart
000001 2010-10-10 08:00 2010-10-10 17:30 2010-10-10 08:02 2010-10-10 17:33 2010-10-10 08:02
000001 2010-10-11 08:00 2010-10-11 17:30 2010-10-11 07:48 2010-10-11 17:29 2010-10-11 17:29
000001 2010-10-12 08:00 2010-10-12 17:30 2010-10-12 08:04 2010-10-12 17:28 2010-10-12 08:04 2010-10-12 17:28
000002 2010-10-10 17:30 2010-10-11 05:30 2010-10-10 17:31 2010-10-11 05:35 2010-10-10 17:31
000002 2010-10-11 17:30 2010-10-12 05:30 2010-10-11 17:28 2010-10-12 05:29 2010-10-12 05:29
000002 2010-10-12 17:30 2010-10-13 05:30 2010-10-12 17:32 2010-10-13 05:27 2010-10-12 17:32 2010-10-13 05:27
Để tối ưu hóa truy vấn, tôi sẽ thay đổi chỉ mục của bạn trên bảng quét
CREATE TABLE `tb_scan` (
`scpercode` varchar(6) DEFAULT NULL,
`scscantime` datetime,
KEY `personDate` (`scpercode`, `scscantime` )