2010-07-15 23 views
13
SELECT 
a.foo 
b.bar 
c.foobar 
FROM tableOne AS a 
INNER JOIN tableTwo AS b ON a.pk = b.fk 
LEFT JOIN tableThree AS c ON b.pk = c.fk 
WHERE a.foo = 'something' 
AND c.foobar = 'somethingelse' 

जहां क्लॉज बाएं को एक आंतरिक जुड़ने में बदलता है, उसके बाद और खंड होने के बाद। मैं जो व्यवहार देख रहा हूं वह यह है कि अगर टेबल में 'कुछ नहीं' है तो वहां 0 पंक्तियां वापस आ जाएंगी।बाएं शामिल हो जाते हैं

यदि मैं शामिल खंड में c.foobar = 'someelse' को स्थानांतरित करता हूं तो संग्रहीत जॉइन बाएं जुड़ने जैसा कार्य करेगा।

SELECT 
    a.foo 
    b.bar 
    c.foobar 
    FROM tableOne AS a 
    INNER JOIN tableTwo AS b ON a.pk = b.fk 
    LEFT JOIN tableThree AS c ON b.pk = c.fk 
    AND c.foobar = 'somethingelse' 
    WHERE a.foo = 'something' 

क्या कोई मुझे कुछ दस्तावेज पर बता सकता है कि ऐसा क्यों होता है? आपको बहुत धन्यवाद

उत्तर

31

यह आपके WHERE खंड के कारण है।

जब भी आप एक बाईं के दाईं ओर से कोई मान निर्दिष्ट एक WHERE खंड (जो NOT NULL है), तो आप जरूरी NULL सभी मान को खत्म करने में शामिल होने और यह अनिवार्य रूप से एक INNER JOIN हो जाता है।

यदि आप लिखते हैं, AND c.foobar = 'somethingelse' OR c.foobar IS NULL जो समस्या का समाधान करेगा।

आप c.foobar भाग को अपने जुड़ने की भविष्यवाणी में भी ले जा सकते हैं, और यह भी समस्या को हल करेगा।

+0

+1। अच्छा स्पष्टीकरण। –

+0

@ डेवमार्कल वह वही मामला है जब मैं समूह में बाएं या दाएं भाग में दाएं हिस्से से मूल्य निर्दिष्ट करता हूं। (मेरा मतलब है कि यह बाएं से भीतरी में परिवर्तित हो जाएगा) –

+0

@ डेव मार्कल क्या आप जानते हैं कि तेज़ी से क्या होगा, WHERE क्लॉज या जॉइन इस तरह के मामले में भविष्यवाणी करेगा? – PerPlexSystem

3

कारण आप इसे देख रहे हैं क्योंकि बाएं शामिलके सभी स्तंभों को उन पंक्तियों के लिए सेट करता है जो c (यानी शामिल नहीं हो सकते हैं) में मौजूद नहीं हैं। इसका मतलब है कि तुलना c.foobar = 'somethingelse' सच नहीं है, यही कारण है कि उन पंक्तियों को वापस नहीं किया जा रहा है।

यदि आप c.foobar = 'somethingelse' को शामिल स्थिति में स्थानांतरित करते हैं, तो उस स्थिति में अभी भी उन पंक्तियों को वापस कर रहा है (हालांकि शून्य मानों के बावजूद) जब स्थिति सत्य नहीं है।

0

जॉइन अपना काम कर रहे हैं, फिर जहां रिकॉर्ड हटा रहे हैं जहां c.foobar <> 'someelse'।

प्रभाव एक आंतरिक शामिल होने जैसा दिखता है लेकिन वास्तव में नहीं है।

0

एक बाएं बाएं टेबल (तालिका में आपके दो में) से सब कुछ लौटता है और दाईं ओर तालिका से मेल खाने वाली किसी भी मिलान पंक्ति (तालिका आपके उदाहरण में तीन)। जब आप बाएं जुड़ने के दाहिने तरफ (यानी टेबल थ्री) पर कुछ फ़िल्टर करते हैं और आप गैर मिलान वाले मानों के लिए खाते नहीं हैं, तो आपको प्रभावी रूप से यह आवश्यक होना चाहिए कि एक मूल्य मौजूद है और यह मान 'कुछ' है जो आंतरिक के बराबर है में शामिल हो। तुम क्या करने की कोशिश कर रहे हैं जो 'कुछ' के एक foobar मूल्य के साथ tableThree में एक पंक्ति की जरूरत नहीं है सब tableTwo पंक्तियों को मिल रहा है, तो आप खंड पर में छानने स्थानांतरित कर सकते हैं:

Select a.foo, b.bar, c.foobar 
From tableOne As a 
    Inner Join tableTwo as b 
     On b.fk = a.pk 
    Left Join tableThree as c 
     On c.fk = b.pk 
      And c.foobar = 'something' 
Where a.foo = 'something' 
    And c.pk Is Null 

अंतिम अलावा , c.pk Is Null उन मानों के लिए फ़िल्टर जिनके पास तालिका नहीं है 'कुछ' के foobar मान के साथ तीन मान। अगर बस तालिका को देखना चाहते हैं तो तीन मान जब उनके पास 'कुछ' (और अन्यथा nulls) का foobar मान होता है, तो अतिरिक्त फ़िल्टर I को हटा दें I c.pk Is Null जोड़ा गया।

0

1 मामले (जहां c.foobar में है, जहां खंड) c.foobar के आधार पर फ़िल्टर होता मिलती है के बाद हुई है (वे सही ढंग से होते हैं) है, तो आप को प्रभावी ढंग से फ़िल्टर कर बाहर सभी परिणामी रिकॉर्ड है कि वहां 'somethingelse' नहीं है ..

2 मामले c.foobar में शामिल होने का हिस्सा है, तो यह समय में शामिल होने पर मूल्यांकन करता है और बस में शामिल होने के उत्पादन को नियंत्रित करता है, और नहीं अंतिम recordset (null जहां में शामिल होने में विफल रहता है देता है) ..

0

वाम जॉइन एनयूएलएल पैदा करता है जहां कोई मिलान पंक्ति नहीं होती है। इस मामले में, गैर-मिलान पंक्तियों के लिए c.foobar NULL होगा। लेकिन आपका WHERE क्लॉज एक विशिष्ट मान की तलाश में है: 'someelse', और इसलिए सभी नल मानों को फ़िल्टर करेगा। चूंकि एक इंटर्न जॉइन भी दाएं तरफ कोई नल मूल्य नहीं बनाता है, दोनों एक जैसा दिखते हैं। आप शून्य मानों को वापस आने की अनुमति देने के लिए 'OR c.foobar IS NULL' जोड़ सकते हैं।

जब आप ऑन क्लॉज पर स्थिति को स्थानांतरित करते हैं, तो यह अंतिम फ़िल्टर की बजाय जॉइन पंक्ति मिलान का हिस्सा बन जाता है। जॉइन मैच असफल हो सकता है, और बाहरी जुड़ने के बाद उन मामलों पर एनयूएलएल वापस आते हैं जहां 'सी.फोोबार' पूर्ण है या 'कुछ नहीं' है।

1

'जहां' खंड में शामिल होने के बाद किया जाता है देखें। यह आंतरिक जुड़ने के लिए कोई फर्क नहीं पड़ता लेकिन बाहरी जुड़ने के लिए मायने रखता है।

छोटा उदाहरण

SELECT b.bar,c.foobar FROM tableTwo AS b LEFT JOIN tableThree AS c ON b.pk=c.fk WHERE c.foobar='somethingelse' 

Raw data     Outer Join Result  Select Result 
b.pk c.fk c.foorbar  b.pk c.fk c.foorbar  c.foorbar 
1 1 something  1 1 something  <not in result set> 
1 1 somethingelse 1 1 somethingelse somethingelse 


SELECT b.bar,c.foobar FROM tableTwo AS b LEFT JOIN tableThree AS c ON b.pk=c.fk AND c.foobar='somethingelse' 

Raw data     Outer Join Result  Select Result 
b.pk c.fk c.foorbar  b.pk c.fk c.foorbar  c.foorbar 
1 1 something  1 null null   null 
1 1 somethingelse 1 1 somethingelse somethingelse 
0

यह एक वाम बंद नहीं करता शामिल हों में एक अंदरूनी शामिल हों, सोचा प्रभाव एक ही प्रतीत हो सकता है। जब आप सेट जहां हालत

और c.foobar = 'somethingelse'

आप सभी मामलों है कि एक वाम की अनुमति: नष्ट कर रहे के रूप में यह होता है कार्य करने के लिए शामिल हों। इस मामले में, c.foobar के लिए कुछ मान पूर्ण होंगे। जॉइन हालत पर इसे सेट करने से अभी भी गैर-मिलान वाले बाएं जॉइन परिणाम की अनुमति मिलती है, केवल सी परिणामों के लिए जो कुछ भी लौटाया जाता है उसे प्रतिबंधित करता है।

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