सबसे पहले, इस प्रश्न को अपने दूसरे से पोस्ट करने पर बेहतर। आपको कई रिकॉर्ड मिल रहे थे, इसका कारण यह है कि एक व्यक्ति अपनी शिफ्ट के आधार पर एक ही दिन में कई बार अंदर और बाहर देखता है। अब इसका समाधान कैसे करें।
MySQL में, आप चुनिंदा FROM क्लॉज के हिस्से के रूप में "@" वेरिएबल का उपयोग करके इनलाइन वैरिएबल डिक्लेरेशन और असाइनमेंट कर सकते हैं। मैं जो शुरू कर रहा हूं वह कुछ @variables के साथ कार्य दिवस से शिफ्ट टेबल (और मुझे लगता है कि अब मैं इसे समझता हूं) में एक साधारण जुड़ाव है।
प्रत्येक व्यक्ति के लिए, शिफ्ट में शामिल होने के लिए, मैं प्री-कंप्यूटिंग कर रहा हूं जहां शिफ्ट के बीच में उसी दिन बनाम अगले दिन होता है। साथ ही, शुरुआती 2 और अंत 2 संभावित क्लॉक-इन बनाम क्लॉक-आउट के लिए आउटलेयर प्रतीत होते हैं। उदाहरण:व्यक्ति 1 शिफ्ट में काम कर रहा है। शिफ्ट 1 को किसी भी दिन के काम के लिए परिभाषित किया गया है
shiftcode shiftbegin2 shiftbegin shiftmid shiftend shiftend2
1 04:00:00 08:00:00 12:00:00 17:30:00 21:30:00
इसलिए, मैं इसकी व्याख्या इस तरह कर रहा हूं जैसे कि मैं 28 जून को काम कर रहा हूं, शिफ्ट 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
इसी तरह, शिफ्ट 2 के लिए जो रात भर चलेगी
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
इसलिए, यदि यह सब सही है, तो मेरी आंतरिक क्वेरी प्रत्येक व्यक्ति के लिए इन सभी श्रेणियों को पूर्व-निर्धारित कर रही है, इसलिए मेरे पास प्रति व्यक्ति प्रति कार्य दिवस केवल 1 रिकॉर्ड होगा, भले ही नीचे के माध्यम से कितने भी स्कैन हों।
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
@midDay और @endDay की इनलाइन कंप्यूटिंग इसलिए है कि मुझे स्कैन किए गए टाइम क्लॉक टेबल में शामिल होने के बारे में चिंता करने की ज़रूरत नहीं है और बाकी सभी के बीच में 1 दिन जोड़ते रहें। तो, इस प्रश्न के अंत में, मैं कुछ इस तरह से समाप्त करूंगा ... व्यक्ति 1 सामान्य शिफ्ट और व्यक्ति 2 रात की पाली के बीच सूचना, गणना की गई समाप्ति तिथि रोल-ओवर तिथियां भी दिखाती है
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
आप इस क्वेरी से अतिरिक्त कॉलम हटा सकते हैं, लेकिन मैंने सभी को शामिल किया है ताकि आप देख सकें/पुष्टि कर सकें कि प्रत्येक पंक्ति और निर्धारित कार्य की तारीख पर विचार करने के लिए मूल्य क्या हैं। संक्षिप्त सूची जिसकी मुझे अभी भी आवश्यकता होगी वह है
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
इसलिए, यदि उपरोक्त सटीक है, तो अब हमें इस क्वेरी से गणना की गई अधिकतम सीमा के आधार पर प्रत्येक व्यक्ति के लिए घड़ी को अंदर और बाहर प्राप्त करना होगा जो प्रति दिन एक से अधिक रिकॉर्ड कर सकता है
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
तो यहां, मैं किसी भी तारीख के लिए स्कैन समय में जल्द से जल्द घड़ी और अधिकतम घड़ी के भीतर शामिल हो रहा हूं और यह निर्धारित करने के आधार के रूप में मिडशिफ्ट का उपयोग कर रहा हूं कि क्या वे देर से बनाम जल्दी छोड़ने में देखे गए हैं। मैंने किसी दिए गए व्यक्ति/शिफ्ट के आगमन और प्रस्थान के लिए अतिरिक्त MIN() और MAX() जोड़ा है, बस यह पुष्टि करने के लिए कि आप क्या करते हैं और क्या देखना चाहिए।
मैक्स (आईएफ ()) का उद्देश्य केवल देर से/प्रारंभिक स्थिति पर कब्जा करना है यदि वे हुआ है। चूंकि समूह प्रति शिफ्ट है, पहला रिकॉर्ड (घड़ी में) देर से हो सकता है और आप उस समय को चाहते हैं, लेकिन क्लॉक आउट के लिए दूसरा रिकॉर्ड मध्य-शिफ्ट के समय के माध्यम से लागू नहीं होता है और इस प्रकार रिक्त होगा। इसी तरह एक शिफ्ट से जल्दी प्रस्थान का पता लगाने के लिए।
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;
मैंने आपके द्वारा प्रदान किए गए डेटा से टेबल और नमूना डेटा बनाया है (जिनमें से आपका कुछ डेटा नमूना तिथियों और श्रेणियों से मेल नहीं खाता है, इसलिए मैंने ऐसा करने के लिए समायोजित किया है)।
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' );
नमूना डेटा प्रत्येक व्यक्ति को 1 के साथ दिखाता है:देर से आना, 2:जल्दी प्रस्थान करना, 3:देर से आना और जल्दी प्रस्थान करना।
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
क्वेरी को ऑप्टिमाइज़ करने के लिए, मैं स्कैन टेबल पर आपकी अनुक्रमणिका बदल दूंगा
CREATE TABLE `tb_scan` (
`scpercode` varchar(6) DEFAULT NULL,
`scscantime` datetime,
KEY `personDate` (`scpercode`, `scscantime` )