Mysql
 sql >> डेटाबेस >  >> RDS >> Mysql

एक समग्र सूचकांक के साथ या पूरी तरह से उपयोग करने के लिए एकाधिक बाएं जॉइन कैसे करें? (भाग 2)

सबसे पहले, इस प्रश्न को अपने दूसरे से पोस्ट करने पर बेहतर। आपको कई रिकॉर्ड मिल रहे थे, इसका कारण यह है कि एक व्यक्ति अपनी शिफ्ट के आधार पर एक ही दिन में कई बार अंदर और बाहर देखता है। अब इसका समाधान कैसे करें।

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` )



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. मैं एक ही सर्वर पर एकाधिक डोमेन में PHP सत्र कैसे बनाए रखूं?

  2. यादृच्छिक समय पर क्वेरी अंत चरण बहुत लंबा है

  3. क्रॉन टैब का उपयोग करके MySQL डेटाबेस बैकअप कैसे लें और इसे हर रात Amazon s3 में कैसे डालें?

  4. MySQL में 640k पंक्तियों को अद्यतन करने का प्रयास क्वेरी के दौरान MySQL सर्वर से कनेक्शन खो जाता है

  5. MySQL परिणामों को कैसे व्यवस्थित और समूहित करें