2014-10-30 13 views
6

मेरे पास ग्राहक तालिका और ऑर्डर तालिका है। सभी ग्राहकों ने ऑर्डर नहीं दिया है, इसलिए सभी ग्राहक आईडी ऑर्डर टेबल पर नहीं हैं। मैं चाहता हूं कि मेरा परिणाम केवल उस ग्राहक तालिका के मान दिखाए जो ऑर्डर नहीं करता है, इसलिए ऑर्डर आईडी कॉलम को शून्य के रूप में दिखाना चाहिए। निम्नलिखित कोड काम करता है:यह कथन केवल WHERE के साथ क्यों काम करता है?

SELECT c.CustomerID, c.CustomerName, o.OrderID 
    FROM Customers c 
    LEFT OUTER JOIN Orders o 
ON c.CustomerID = o.CustomerID WHERE o.OrderID IS NULL 

लेकिन एक मैं मूल रूप से करने की कोशिश की नहीं करता है:

SELECT c.CustomerID, c.CustomerName, o.OrderID 
    FROM Customers c 
    LEFT OUTER JOIN Orders o 
ON c.CustomerID = o.CustomerID AND o.OrderID IS NULL 

यह एक के बजाय ग्राहकों की मेज पर सभी मूल्यों को दर्शाता है, लेकिन उनमें से सभी उनके OrderID के लिए पर अशक्त है

मुझे नहीं लगता कि मैं वास्तव में अंतर को समझता हूं, क्योंकि मुझे लगता है कि यह दोनों एक ही चीज़ को वापस करने के लिए समझ में आएगा।

+0

मैं सहजता से समझता हूं कि आप ऐसा क्यों सोचेंगे, लेकिन मुझे लगता है कि कारण यह है कि 'ऑन' का उपयोग किसी दिए गए शर्त पर तालिकाओं में शामिल होने के लिए किया जाता है। आप जो करने की कोशिश कर रहे हैं वह पंक्तियों की तलाश है जहां एक शर्त सच है। मुझे नहीं पता कि यह सच के करीब कहीं भी है, लेकिन इस तरह मैं इसके बारे में सोचने आया हूं और जानता हूं कि इसका उपयोग कब किया जाए। – AdamMc331

+0

एंड ओ। ऑर्डर आईडी वह है जो इसे गड़बड़ कर रहा है। जब तक यह और .... स्थिति को हिट नहीं करता तब तक यह सही तरीके से काम करेगा। – rvphx

उत्तर

2

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

देखो:

 
Table A   Table B 
┌──────┬──────┐ ┌──────┬──────┐ 
│field1│field2│ │field3│field4│ 
├──────┼──────┤ ├──────┼──────┤ 
│A  │1  │ │1  │One │ 
│B  │2  │ │3  │Three │ 
│C  │3  │ └──────┴──────┘ 
└──────┴──────┘ 

टेबल 'आंतरिक (field2 के बीच और फ़ील्ड 3) है में शामिल होने:

 
┌──────┬──────┬──────┬──────┐ 
│field1│field2│field3│field4│ 
├──────┼──────┤──────┼──────┤ 
│A  │1  │1  │One │ 
│C  │3  │3  │Three │ 
└──────┴──────┴──────┴──────┘ 

लेकिन तालिकाएं' बाहरी में शामिल होने आप हर रिकॉर्ड देने के लिए है, और यदि कोई मैच नहीं है, तो इसके बजाय नल डालें।

 
┌──────┬──────┬──────┬──────┐ 
│field1│field2│field3│field4│ 
├──────┼──────┤──────┼──────┤ 
│A  │1  │1  │One │ 
│B  │2  │NULL │NULL │⬅︎ No match 
│C  │3  │3  │Three │ 
└──────┴──────┴──────┴──────┘ 

अब अगर वहाँ table2 में कोई मिलान बिल्कुल रहे हैं तो क्या होगा? उदाहरण के लिए, यदि आपने ऑन क्लॉज में एक असंभव स्थिति जोड़ा है? फिर परिणाम में सभी रिकॉर्ड "कोई मैच"

 
┌──────┬──────┬──────┬──────┐ 
│field1│field2│field3│field4│ 
├──────┼──────┤──────┼──────┤ 
│A  │1  │NULL │NULL │⬅︎ No match (because of impossible condition) 
│B  │2  │NULL │NULL │⬅︎ No match (because of impossible condition) 
│C  │3  │NULL │NULL │⬅︎ No match (because of impossible condition) 
└──────┴──────┴──────┴──────┘ 

कैसा लगेगा अगर कोई मैच था क्योंकि वहाँ की गई ID वाला तालिका 2 में कोई रिकॉर्ड नहीं था, या अगर कोई था नहीं तो यह कोई फर्क नहीं पड़ता मैच क्योंकि आपने एक असंभव स्थिति जोड़ दी है। बाहरी जुड़ने का नतीजा यह है कि फ़ील्ड जो टेबल 2 से आते थे उन्हें नल के साथ बदल दिया जाएगा। क्योंकि इस तरह बाहरी जुड़ाव परिभाषित किया जाता है।


अब असली दुनिया तालिकाओं के लिए:

आप वास्तव में आदेश जिसका OrderID रिक्त है में किसी भी रिकॉर्ड नहीं है (जब तक आप यह बहुत बुरी तरह से तैयार किया गया है)। इसलिए यदि आप उस शर्त को ऑन क्लॉज में डालते हैं, तो उसे आपके मानदंडों को पूरा करने वाले कोई रिकॉर्ड नहीं मिलेगा।

ऐसे मामले में, क्योंकि यह एक बाहरी (बाएं) शामिल है, इसलिए आप सभी मूल ग्राहक रिकॉर्ड प्राप्त करते हैं, और क्योंकि कोई मिलान नहीं होता है, उनमें से प्रत्येक के पास ऑर्डर से सभी शून्य होते हैं।

यदि आप WHERE में स्थिति डालते हैं, तो आप वास्तव में बाएं शामिल होने के इस व्यवहार का अच्छा उपयोग कर रहे थे। आप प्रत्येक ग्राहक से अपने आदेश के साथ मेल खाते थे। यदि कोई मैच था - ठीक है, तो आपको वास्तविक ऑर्डर आईडी मिल गई है। लेकिन मामलों में कोई मिलान नहीं था - जिन्हें आप ढूंढ रहे हैं - यह एक शून्य ऑर्डर आईडी जोड़ता है।

जहां खंड तब आपको केवल रिकॉर्ड देता है जहां यह हुआ था। यही वह रिकॉर्ड है जो ऑर्डर में मिलान करने वाला आदेश नहीं था।

+0

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

+0

@ फ्रॉस्टीस्ट्रा के रूप में क्यों सेट करता है ऑर्डरआईडी में नल मान का अर्थ है कि कोई रिकॉर्ड मैचों मानदंडों पर नहीं है 'सी। कस्टमर आईडी = ओ। कस्टमर आईडी और ओ.ऑर्डरिड न्यूल'। –

+0

@ फ्रॉस्टीस्ट्रा मैंने अपने उत्तर में बाहरी जुड़ने की प्रकृति के बारे में कुछ स्पष्टीकरण जोड़ा, जो मुझे आशा है कि आपको कारण समझने में मदद मिलेगी। – RealSkeptic

1

यह बस इतना नहीं है कि एसक्यूएल कैसे डिज़ाइन किया गया है। से http://dev.mysql.com/doc/refman/5.0/en/join.html

पर के साथ प्रयोग किया conditional_expr रूप है कि एक कहां खंड में इस्तेमाल किया जा सकता के किसी भी सशर्त अभिव्यक्ति है। आम तौर पर, आपको उन शर्तों के लिए ऑन क्लॉज का उपयोग करना चाहिए जो तालिकाओं में शामिल होने के तरीके को निर्दिष्ट करते हैं, और परिणाम सेट में इच्छित पंक्तियों को प्रतिबंधित करने के लिए खंड कहां है।

1

पहला वाला टेबल्स में शामिल होने वाला POST है। दूसरा शामिल होने का हिस्सा है।

तो अंग्रेजी में डालने के लिए।

पहले:

Get CustomerID, Name, and OrderID from 
Customers Link to Orders where CustomerID matches 
Show where link failed 

दूसरा:

Get CustomerID, Name, and OrderID from 
Customers Link to Orders where CustomerID matches and Order ID is null 

सभी लिंक दूसरे में विफल रहते हैं, अपने परिणामों को फ़िल्टर करने के लिए कुछ भी नहीं छोड़ रहा है।

3

LEFT OUTER JOIN का उपयोग करके आप Customers मेज से सभी रिकॉर्ड मिलता है। तो आपके AND o.OrderID IS NULL हालत फ़िल्टर केवल Orders तालिका से रिकॉर्ड हैं लेकिन Customers से रिकॉर्ड नहीं हैं। लेकिन आपको Customers तालिका फ़िल्टर करने की आवश्यकता है और यह JOIN के प्रकार के कारण काम नहीं करता है।

इस बीच WHERE स्थिति का उपयोग पूरे रिकॉर्डसेट पर जॉइन के प्रकार पर ध्यान दिए बिना किया जाता है। LEFT OUTER JOIN को INNER JOIN के साथ प्रतिस्थापित करने का प्रयास करें और आपको दोनों चयनों के लिए एक ही परिणाम मिलते हैं।

अपने दूसरे चयन में आपको o.OrderID के लिए कुल मान मिलते हैं क्योंकि आपने निर्दिष्ट किया है कि यह आपकी स्थिति AND o.OrderID IS NULL में पूर्ण होना चाहिए। Orders तालिका में ऐसा कोई रिकॉर्ड मौजूद नहीं है और इस प्रकार NULL मान का अर्थ है कि कोई रिकॉर्ड मानदंड ON c.CustomerID = o.CustomerID AND o.OrderID IS NULL नहीं है।

1

दूसरी क्वेरी के लिए आपकी शामिल स्थिति प्रत्येक पंक्ति के लिए गलत है। अगर ऑर्डर टेबल में ग्राहक आईडी है तो उसके पास ऑर्डर आईडी भी होगा। प्रत्येक पंक्ति को शामिल करने के बाद शामिल होने के "बाएं" हिस्से को बाएं टेबल (ग्राहक) से सभी बहिष्कृत पंक्तियों को वापस लाया जा रहा है। इस मामले में यह उन सभी को वापस लाता है।

पहली क्वेरी के लिए यह आपकी पंक्तियों पर केवल झूठी है, इसलिए बाएं बस उन पंक्तियों को पुनर्स्थापित करते हैं। और फिर वह स्थिति उन पंक्तियों को निकाल सकती है जिन्हें आप नहीं चाहते हैं।

1

तालिका ## ग्राहक बनाएँ (ईद nvarchar (5)) तालिका ## आदेश (Order_No पूर्णांक, आईडी nvarchar (5))

## ग्राहक मूल्यों में डालें ('ए'), ('बनाएं बी '), (' सी ')

## मूल्यों में डालें (1,' ए '), (2,' बी '), (3,' बी ')

चुनें सी। * ## ग्राहक सी से ## ऑर्डर ओ पर c.Id = o.id पर शामिल हों, जहां o.Order_No शून्य है

सीआई का चयन करें घ, o.order_no ग्राहक ग से ## में शामिल होने c.Id = o.id पर ओ आदेश छोड़ दिया ## और o.Order_No ## ग्राहक ग से

c.id करें नल है, o.order_no c.Id = o.id पर छोड़ दिया शामिल होने के ## आदेश ओ और o.Order_No रिक्त नहीं है

यह अपने आप कोशिश जहां खंड एक फिल्टर

1

एक बाएं बाहरी जॉइन बाएं (पहली) तालिका से बेजोड़ पंक्तियों को सुरक्षित रखता है, जो उन्हें सही (दूसरी) तालिका के आकार में एक पूर्ण पंक्ति के साथ जोड़ता है। चलिए एक ठोस उदाहरण लेते हैं। कहो, ग्राहकों तालिका {c1,"n1"}, {c2,"n2"} है और आदेश {c1, o1} 1 मामला है: वाम बाहरी में शामिल होने के परिणाम होगा:

{c1,"n1", o1}, {c2,"n2", null} 

अब, आप जहां और "और" के अंतर पता है। जहां पता चलता है कि आपके पास शून्य ऑर्डरिड है, और, ऐसा कोई मामला नहीं है जहां ग्राहक आईडी मेल खाता है और ऑर्डर आईडी शून्य है

6

यह जानना महत्वपूर्ण है कि दो प्रश्न बहुत अलग हैं। पहली क्वेरी है:

SELECT c.CustomerID, c.CustomerName, o.OrderID 
FROM Customers c LEFT OUTER JOIN 
    Orders o 
    ON c.CustomerID = o.CustomerID 
WHERE o.OrderID IS NULL; 

यह सभी ग्राहकों के लिए है कि कोई इसी आदेश देता है (या o.OrderId बातिल है)। ऐसा इसलिए होता है क्योंकि left outer join सभी पंक्तियों को पहली तालिका में रखता है। यदि कोई मिलान नहीं है, तो दूसरी तालिका के सभी कॉलम NULL हैं और where खंड इन कॉलम का चयन करेगा।

दूसरा प्रश्न:

SELECT c.CustomerID, c.CustomerName, o.OrderID 
FROM Customers c LEFT OUTER JOIN 
    Orders o 
    ON c.CustomerID = o.CustomerID AND 
     o.OrderID IS NULL; 

सभी पंक्तियों सभी ग्राहकों पाता है और यह भी हो जाता है आदेश की जानकारी जहां OrderId रिक्त है, यदि कोई इस तरह के रिकॉर्ड मौजूद हैं। Customers का कोई फ़िल्टरिंग नहीं है, क्योंकि left outer join गारंटी देता है कि पहली तालिका से सभी पंक्तियां परिणाम सेट में हैं।

मुझे आश्चर्य होगा अगर OrderId नामक फ़ील्ड ने कभी भी NULL मानों को लिया। लेकिन, प्रत्येक क्वेरी मान्य एसक्यूएल है और प्रत्येक कुछ उपयोगी करता है। हालांकि, उनमें से केवल एक ही है जो आप चाहते हैं।

संबंधित मुद्दे