यदि "अनुपस्थिति" को emp_tx
में एक पंक्ति के गैर-उपस्थिति के रूप में परिभाषित किया गया है किसी विशेष empcode
. के लिए तालिका किसी विशेष तिथि के लिए (तारीख =मध्यरात्रि से मध्यरात्रि 24 घंटे की अवधि), और ...
यदि उस तिथि के लिए "अनुपस्थिति" नहीं दिखाना स्वीकार्य है जब emp_tx
में कोई लेनदेन नहीं है उस तिथि के लिए तालिका (अर्थात उस तिथि को छोड़ दें जब उस तिथि पर सभी एम्पकोड अनुपस्थित हों), फिर ...
आप इस तरह की क्वेरी के साथ निर्दिष्ट परिणाम सेट के पहले चार कॉलम प्राप्त कर सकते हैं:(अनचाहे)
SELECT m.empcode AS `EmpCode`
, m.name AS `EmpName`
, m.dept AS `Department`
, d.dt AS `AbsentDate`
FROM ( SELECT DATE(t.s_date) AS dt
FROM emp_tx t
WHERE t.s_date >= '2012-12-12'
AND t.s_date < DATE_ADD( '2012-12-20' ,INTERVAL 1 DAY)
GROUP BY DATE(t.s_date)
ORDER BY DATE(t.s_date)
) d
CROSS
JOIN master m
LEFT
JOIN emp_tx p
ON p.s_date >= d.dt
AND p.s_date < d.dt + INTERVAL 1 DAY
AND p.empcode = m.empcode
WHERE p.empcode IS NULL
ORDER
BY m.empcode
, d.dt
वह पाँचवाँ स्तंभ प्राप्त करना TotalNoofAbsent
उसी परिणाम में वापस आना संभव है, लेकिन यह उस क्वेरी को वास्तव में गड़बड़ कर देगा। लौटाए गए परिणामसेट को संसाधित करते समय, इस विवरण को ग्राहक पक्ष पर अधिक कुशलता से संभाला जा सकता है।
क्वेरी कैसे काम करती है
इनलाइन दृश्य को d
. के रूप में उपनामित किया गया है हमें "तारीख" मानों का एक सेट मिलता है जिसे हम जांच रहे हैं। emp_tx
का उपयोग करना तालिका इन "दिनांक" मानों के स्रोत के रूप में ऐसा करने का एक सुविधाजनक तरीका है। नहीं DATE()
फ़ंक्शन DATETIME तर्क का केवल "तारीख" भाग लौटा रहा है; हम एक GROUP BY
. का उपयोग कर रहे हैं तिथियों की एक अलग सूची प्राप्त करने के लिए (यानी कोई डुप्लिकेट मान नहीं)। (इस इनलाइन व्यू क्वेरी के साथ हम क्या कर रहे हैं, तर्क के रूप में पारित दो मानों के बीच DATE मानों का एक अलग सेट है। DATE मानों की सूची बनाने के अन्य, अधिक शामिल तरीके हैं।)
जब तक प्रत्येक "तारीख" मान जिसे आप "अनुपस्थिति" मानेंगे, तालिका में कहीं दिखाई देता है (अर्थात, कम से कम एक empcode
प्रत्येक तिथि पर एक लेन-देन था जो ब्याज की है), और जब तक emp_tx
में पंक्तियों की संख्या है तालिका अत्यधिक नहीं है, तो इनलाइन दृश्य क्वेरी उचित रूप से अच्छी तरह से काम करेगी।
(नोट:इनलाइन व्यू में क्वेरी को अलग से चलाया जा सकता है, यह सत्यापित करने के लिए कि परिणाम सही हैं और जैसा कि हम उम्मीद करते हैं।)
अगला कदम इनलाइन दृश्य से परिणाम लेना और CROSS JOIN
करना है ऑपरेशन (एक कार्टेशियन उत्पाद उत्पन्न करने के लिए) हर empcode
. से मेल खाने के लिए हर date
. के साथ इनलाइन दृश्य से लौटा। इस ऑपरेशन का परिणाम "उपस्थिति" की हर संभावित घटना का प्रतिनिधित्व करता है।
क्वेरी में अंतिम चरण LEFT JOIN
का उपयोग करके "एंटी-जॉइन" ऑपरेशन करना है और एक WHERE IS NULL
विधेय LEFT JOIN
(बाहरी जुड़ाव) हर संभव उपस्थिति घटना (बाईं ओर से) देता है, जिसमें वे शामिल हैं जिनकी emp_tx
से मेल खाने वाली पंक्ति (उपस्थिति रिकॉर्ड) नहीं है टेबल।
"ट्रिक" एक विधेय (WHERE क्लॉज में) को शामिल करना है जो उन सभी पंक्तियों को छोड़ देता है जहां एक मिलान उपस्थिति रिकॉर्ड पाया गया था, ताकि हमारे पास जो कुछ बचा है वह empcode
के सभी संयोजन हैं। और date
(संभावित उपस्थिति घटनाएं) जहां कोई मिलान उपस्थिति लेनदेन नहीं था।
(नोट:मैंने विधेय में s_date (DATETIME) कॉलम "नंगे" के संदर्भों को उद्देश्यपूर्ण रूप से छोड़ दिया है, और उपयोग की गई श्रेणी विधेय। यह MySQL को एक उपयुक्त इंडेक्स का प्रभावी उपयोग करने की अनुमति देगा जिसमें वह कॉलम शामिल है।)
यदि हम किसी फ़ंक्शन के अंदर विधेय में कॉलम संदर्भों को लपेटना चाहते हैं उदा। DATE(p.s_date)
, तो MySQL s_date
. पर किसी अनुक्रमणिका का प्रभावी उपयोग करने में सक्षम नहीं होगा कॉलम।
जैसा कि टिप्पणियों में से एक (आपके प्रश्न पर) बताता है, हम किसी कर्मचारी को "आने" या "बाहर जाने" के रूप में चिह्नित करने वाले लेनदेन के बीच कोई भेद नहीं कर रहे हैं। हम केवल 24 घंटे की "मध्यरात्रि से मध्यरात्रि" अवधि में उस एम्कोड के लिए लेनदेन के अस्तित्व की तलाश कर रहे हैं।
समान परिणाम सेट प्राप्त करने के अन्य तरीके हैं, लेकिन "एंटी-जॉइन" पैटर्न आमतौर पर बड़े सेट के साथ सर्वश्रेष्ठ प्रदर्शन देने के लिए निकलता है।
सर्वोत्तम प्रदर्शन के लिए, आप शायद इंडेक्स को कवर करना चाहेंगे:
... ON master (empcode, name, dept)
... ON emp_tx (s_date, empcode)