SQL एक तालिका में गैर-मौजूद पंक्तियों के साथ पंक्तियों को दिखाने के लिए क्वेरी से जुड़ता है


12

मैं कर्मचारी समय रिकॉर्ड के लिए कुछ रिपोर्टिंग करने की कोशिश कर रहा हूं।

इस सवाल के लिए हमारे पास दो टेबल हैं। कर्मचारी Membersतालिका में सूचीबद्ध होते हैं और प्रत्येक दिन वे काम की प्रविष्टियों को दर्ज करते हैं जो उन्होंने प्रदर्शन किया है और Time_Entryतालिका में संग्रहीत किया जाता है।

SQL फिडेल के साथ उदाहरण सेटअप: http://sqlfiddle.com/#! -3 / e3806 /7

मैं जिस अंतिम परिणाम के लिए जा रहा हूं वह एक तालिका है जो सभी को Membersएक कॉलम सूची में दिखाती है और फिर अन्य कॉलमों में उद्धृत तिथि के लिए उनके योग के घंटे दिखाएगी।

समस्या यह प्रतीत होती है कि यदि Time_Entryकिसी विशेष सदस्य के लिए तालिका में कोई पंक्ति नहीं है , तो उस सदस्य के लिए अब पंक्ति है। मैंने कई अलग-अलग ज्वाइन प्रकारों की कोशिश की है (लेफ्ट, राईट, इनर, आउटर, फुल आउटर, इत्यादि), लेकिन कोई भी मुझे वह नहीं देना चाहता जो मुझे चाहिए, जो कि होगा (SQL फिडेल में अंतिम उदाहरण के आधार पर):

/*** Desired End Result ***/

Member_ID   | COUNTTime_Entry | TIMEENTRYDATE | SUMHOURS_ACTUAL | SUMHOURS_BILL
ADavis      | 0               | 11-10-2013    | 0               | 0
BTronton    | 0               | 11-10-2013    | 0               | 0
CJones      | 0               | 11-10-2013    | 0               | 0
DSmith      | 0               | 11-10-2013    | 0               | 0
EGirsch     | 1               | 11-10-2013    | 0.92            | 1
FRowden     | 0               | 11-10-2013    | 0               | 0

जब मैं 11-1 की विशिष्ट तिथि के लिए क्वेरी करता हूं, तो मुझे वर्तमान में क्या मिल रहा है:

Member_ID   | COUNTTime_Entry | TIMEENTRYDATE | SUMHOURS_ACTUAL | SUMHOURS_BILL
EGirsch     | 1               | 11-10-2013    | 0.92            | 1

यह एक टाइम एंट्री पंक्ति के आधार पर सही है जो कि ईजीरिस्च के लिए 11-10-2013 की तारीख है, लेकिन मुझे रिपोर्ट प्राप्त करने और अंततः इस जानकारी के लिए एक वेब डैशबोर्ड / रिपोर्ट प्राप्त करने के लिए अन्य सदस्यों के लिए शून्य देखने की आवश्यकता है।

यह मेरा पहला सवाल है, और जब मैंने जॉइन क्वेश्चन आदि की खोज की, तो मुझे पूरी उम्मीद है कि इस फ़ंक्शन को क्या कहा जा सकता है, इसलिए मुझे आशा है कि यह कोई डुप्लिकेट नहीं है और इससे दूसरों को भी इसका हल ढूंढने में मदद मिलेगी इसी तरह की समस्याएं।

जवाबों:


11

SQLfiddle और नमूना डेटा के लिए धन्यवाद! काश इस तरह से और प्रश्न शुरू होते।

यदि आप सभी सदस्यों को इस बात की परवाह किए बिना चाहते हैं कि उनके पास उस तिथि के लिए एक प्रविष्टि है, तो आप चाहते हैं कि ए LEFT OUTER JOIN। आप इस संस्करण के साथ बहुत करीब थे, लेकिन बाहरी जोड़ के साथ एक छोटी सी चाल यह है कि यदि आप WHEREखंड में बाहरी तालिका में एक फिल्टर जोड़ते हैं , तो आप बाहरी जोड़ को एक आंतरिक जोड़ में बदल देते हैं, क्योंकि यह NULLउस तरफ किसी भी पंक्तियों को बाहर कर देगा (क्योंकि यह नहीं पता है NULLकि फ़िल्टर से मेल खाएगा या नहीं)।

मैंने प्रत्येक सदस्य के लिए एक पंक्ति प्राप्त करने के लिए पहली क्वेरी को संशोधित किया:

SELECT Members.Member_ID
      ,Time_Entry.Date_Start
      ,Time_Entry.Hours_Actual
      ,Time_Entry.Hours_Bill
FROM dbo.Members
  LEFT OUTER JOIN dbo.Time_Entry
--^^^^ changed from FULL to LEFT
  ON Members.Member_ID = Time_Entry.Member_ID
  AND Time_Entry.Date_Start = '20131110';
--^^^ changed from WHERE to AND

मैं इसे पढ़ने के लिए एक अभ्यास के रूप में छोड़ दूँगा और इसे अन्य कॉलम, स्वरूपण, COALESCEआदि में जोड़ दूँगा ।

कुछ अन्य नोट:


हारून, प्रतिक्रिया के लिए बहुत बहुत धन्यवाद। यहाँ एसक्यूएल नौसिखिया, और पता नहीं था WHEREऔर के बीच का अंतर AND। मैंने मूल रूप से उपनामों का उपयोग किया था, लेकिन sqlfiddle को यह पसंद नहीं आया इसलिए मैंने अभी पूर्ण प्रारूप दिया। अन्य एसक्यूएल सुझावों के लिए भी धन्यवाद। क्या आप इसके बजाय डेटा 0 की सिफारिश ISNULLया COALESCEकरना चाहेंगे ? एक बार फिर धन्यवाद! NULL
फेयरवेल्डेव

1
@farewelldave मुझे पसंद है क्योंकि यह मानक है और इसकी कार्यक्षमता से अन्य भाषाओं में विचलन नहीं है (तुलना करें कि उदाहरण के लिए SQL सर्वर बनाम VB में ISNULL कैसे काम करता है)। लगभग सभी मामलों में प्रदर्शन अंतर एक को छोड़कर, असंगत है। बहुत अधिक विवरण यहाँ
हारून बर्ट्रेंड

4

जब मुझे अतीत में इस प्रकार की समस्या का सामना करना पड़ा है, तो मैंने लापता पंक्तियों से निपटने में मदद करने के लिए एक "संख्या" तालिका बनाई है ।

मैंने अपनी संख्या तालिका विशेष रूप से तारीखों से निपटने के लिए बनाई है:

CREATE TABLE Dates
(
    dDate DATETIME NOT NULL CONSTRAINT PK_Dates PRIMARY KEY CLUSTERED
);

INSERT INTO Dates (dDate)
SELECT TOP(73049) DATEADD(d, -1, ROW_NUMBER() OVER (ORDER BY o.object_id)) AS dDate
FROM master.sys.objects o, master.sys.objects o1, master.sys.objects o2

यह 1900-01-01 और 2099-12-31 के बीच प्रत्येक तिथि के लिए एक पंक्ति के साथ एक तालिका बनाता है। मैं TOP(73049)अपने उदाहरण में उत्पन्न तिथि सीमा को दिनांक को सीमित करने के लिए उपयोग करता हूं - यदि आप एक अलग तिथि सीमा के साथ काम करते हैं, तो आप उस संख्या को समायोजित कर सकते हैं।

इसके बाद, मैं dDatesतालिका को अपनी क्वेरी में जोड़ता हूं ताकि प्रत्येक तिथि को प्रत्येक श्रेणी के लिए वांछित सीमा में लौटा दिया जाए member_id। परिणाम इस प्रकार Time_Entryतालिका में शामिल किया गया है :

SELECT MD.Member_ID,
    MD.dDate,
    T.Date_Start,
    T.Hours_Actual,
    T.Hours_Bill
FROM 
    (
        SELECT M.Member_ID, D.dDate
        FROM dbo.Dates D, dbo.Members M
        WHERE D.dDate >= '20131110' AND D.dDate < '20131112'
    ) AS MD
    LEFT JOIN dbo.Time_Entry T ON MD.Member_ID = T.Member_ID AND MD.dDate = T.Date_Start
ORDER BY MD.Member_ID, MD.dDate

यह आपको रिपोर्ट के लिए एक तिथि सीमा निर्दिष्ट करने की अनुमति देता है।

आप परिणामों को जोड़कर COALESCE(...)और उसके SUM(...)अनुसार और परिशोधित कर सकते हैं :

SELECT MD.Member_ID,
    MD.dDate,
    T.Date_Start,
    SUM(COALESCE(T.Hours_Actual, 0)) AS TotalHoursActual,
    SUM(COALESCE(T.Hours_Bill, 0)) AS TotalHoursBill
FROM 
    (
        SELECT M.Member_ID, D.dDate
        FROM dbo.Dates D, dbo.Members M
        WHERE D.dDate >= '20131110' AND D.dDate < '20131112'
    ) AS MD
    LEFT JOIN dbo.Time_Entry T ON MD.Member_ID = T.Member_ID AND MD.dDate = T.Date_Start
GROUP BY MD.Member_ID, MD.dDate, T.Date_Start
ORDER BY MD.Member_ID, MD.dDate

यह आपके नमूना डेटा के लिए निम्न आउटपुट में परिणाम करता है:

यहाँ छवि विवरण दर्ज करें


धन्यवाद, मैक्स। आप "नंबर तालिका" के बजाय "टैली टेबल" की खोज करके इस तकनीक के बारे में अच्छी जानकारी प्राप्त कर सकते हैं। वे सेट का उपयोग करके ऑपरेशन में कर्सर / लूप का उपयोग करके संचालन में सुधार करके प्रदर्शन में सुधार करने के लिए महान हैं। रिलेशनल डेटाबेस सेट पसंद करते हैं।
सनकैट

1
@ Suncat2000 - सहमत है, हालांकि मैं "नंबर टेबल" नाम पसंद करता हूं क्योंकि टैली का अर्थ है इसके अलावा, और मेरे अनुभव में, यह पैटर्न शायद ही कभी गणितीय कार्यों के लिए उपयोग किया जाता है। वे कई चीजों के लिए महान हैं, लेकिन निश्चित रूप से एक सबसे बड़ा प्रदर्शन सुधार जो आप प्राप्त कर सकते हैं वह एक आरबीएआर दृष्टिकोण से एक सेट-आधारित दृष्टिकोण तक, एक संख्या तालिका का उपयोग करके हो रहा है।
मैक्स वर्नोन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.