2009-05-21 11 views
214

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

SELECT a.foo, b.foo 
FROM a, b 
WHERE a.x = b.x 

SELECT a.foo, b.foo 
FROM a 
LEFT JOIN b ON a.x = b.x 

अब स्पष्ट रूप से जब आपको बाहरी जुड़ने की आवश्यकता होती है, तो दूसरा वाक्यविन्यास आवश्यक होता है। लेकिन जब आंतरिक प्रवेश करते हैं तो मुझे पहले (या इसके विपरीत) के दूसरे वाक्यविन्यास को क्यों पसंद करना चाहिए?

+1

गुफा: आपको यह कैसे मिला? हालांकि मेरा प्रश्न "मैं कैसे कर सकता हूं" – jmucchiello

+0

से अधिक सर्वोत्तम अभ्यास है, क्योंकि यह सर्वोत्तम अभ्यास है, कृपया इसे विकी बनाएं। –

+0

मुझे नहीं लगता कि किसी ने इन दोनों के प्रदर्शन के बारे में टिप्पणी की है। क्या कोई भी किसी भी महत्वपूर्ण अंतर के बारे में कुछ भी उचित या पुष्टि कर सकता है? – ahnbizcad

उत्तर

280

पुराने वाक्यविन्यास, केवल टेबल सूचीबद्ध करने के साथ, और WHERE खंड का उपयोग करने के लिए मानदंडों को निर्दिष्ट करने के लिए, अधिकांश आधुनिक डेटाबेस में बहिष्कृत किया जा रहा है।

यह केवल शो के लिए नहीं है, पुराने सिंटैक्स में अस्पष्ट होने की संभावना है जब आप इन क्वेरीर और आउटर दोनों का उपयोग उसी क्वेरी में शामिल करते हैं।

मुझे आपको एक उदाहरण दें।

के आप अपने सिस्टम में 3 टेबल है लगता है:

Company 
Department 
Employee 

हर तालिका, कई पंक्तियां हो सकती हैं एक साथ जुड़े हुए। आपको कई कंपनियां मिलीं, और प्रत्येक कंपनी के पास कई विभाग हो सकते हैं, और प्रत्येक विभाग में कई कर्मचारी हो सकते हैं।

ठीक है, तो अब आप निम्न कार्य करना चाहते हैं:

सूची सभी कंपनियों, और उनके सभी विभागों, और अपने सभी कर्मचारियों में शामिल हैं। ध्यान दें कि कुछ कंपनियों के पास अभी तक कोई विभाग नहीं है, लेकिन सुनिश्चित करें कि आप उन्हें भी शामिल करते हैं। सुनिश्चित करें कि आप केवल उन विभागों को पुनर्प्राप्त करें जिनके पास कर्मचारी हैं, लेकिन हमेशा सभी कंपनियों को सूचीबद्ध करते हैं।

SELECT * -- for simplicity 
FROM Company, Department, Employee 
WHERE Company.ID *= Department.CompanyID 
    AND Department.ID = Employee.DepartmentID 

नोट पिछले एक वहाँ आदेश मापदंड है कि आप केवल लोगों के साथ विभागों चाहते को पूरा करने में एक आंतरिक में शामिल होने के यह है कि,:

तो आप ऐसा करते हैं।

ठीक है, तो अब क्या होता है। खैर, समस्या यह है कि यह डेटाबेस इंजन, क्वेरी ऑप्टिमाइज़र, इंडेक्स और टेबल आंकड़ों पर निर्भर करता है। मुझे समझाने दो।

यदि क्वेरी ऑप्टिमाइज़र निर्धारित करता है कि ऐसा करने का तरीका सबसे पहले कंपनी लेना है, तो विभागों को ढूंढें, और फिर कर्मचारियों के साथ आंतरिक संपर्क करें, आपको ऐसी कोई भी कंपनी नहीं मिल रही है जो आपके पास नहीं है विभागों।

इसका कारण यह है कि WHERE खंड निर्धारित करता है कि पंक्तियां अंतिम परिणाम में समाप्त होती हैं, पंक्तियों के अलग-अलग हिस्सों में नहीं।

और इस मामले में, बाएं शामिल होने के कारण, विभाग.आईडी कॉलम न्यूल होगा, और इस प्रकार जब कर्मचारी के लिए INNER जॉइन में आता है, तो कर्मचारी पंक्ति के लिए उस बाधा को पूरा करने का कोई तरीका नहीं है, और इसलिए यह प्रकट नहीं होगा।

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

तो पुराना वाक्यविन्यास संदिग्ध है। क्वेरी संकेतों से निपटने के बिना, आप जो चाहते हैं उसे निर्दिष्ट करने का कोई तरीका नहीं है, और कुछ डेटाबेसों का कोई तरीका नहीं है।

नया वाक्यविन्यास दर्ज करें, इसके साथ आप चुन सकते हैं।

SELECT * 
FROM Company 
    LEFT JOIN (
     Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID 
    ) ON Company.ID = Department.CompanyID 

यहाँ आप निर्दिष्ट करते हैं कि आप चाहते हैं एक में शामिल होने के रूप में विभाग-कर्मचारी के लिए किया जाना शामिल हों:

उदाहरण के लिए, यदि आप सभी कंपनियों चाहते हैं, समस्या वर्णन कहा गया है, यह आप जो लिखते हैं होता है , और उसके बाद कंपनियों के परिणामों में शामिल हो गए।

इसके अतिरिक्त, मान लीजिए कि आप केवल उन विभागों को चाहते हैं जिनमें उनके नाम पर अक्षर एक्स शामिल है। फिर, पुरानी शैली के साथ जुड़ जाता है, तो आप कंपनी के रूप में अच्छी तरह से खोने, अगर यह अपने नाम में एक एक्स के साथ किसी भी विभागों नहीं है जोखिम है, लेकिन नई वाक्य रचना के साथ, आप ऐसा कर सकते हैं:

SELECT * 
FROM Company 
    LEFT JOIN (
     Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID 
    ) ON Company.ID = Department.CompanyID AND Department.Name LIKE '%X%' 

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

यही कारण है कि, अन्य विक्रेताओं के बीच, माइक्रोसॉफ्ट ने पुराने बाहरी सिंटैक्स में शामिल किया है, लेकिन पुराना आंतरिक सिंटैक्स नहीं है, क्योंकि SQL Server 2005 और ऊपर के बाद से। पुराने स्टाइल बाहरी सिंटैक्स का उपयोग करते हुए, Microsoft SQL Server 2005 या 2008 पर चल रहे डेटाबेस से बात करने का एकमात्र तरीका है, उस डेटाबेस को 8.0 संगतता मोड (उर्फ SQL Server 2000) में सेट करना है।

इसके अतिरिक्त, पुराने विकल्प, क्वेरी ऑप्टिमाइज़र पर टेबल का एक समूह फेंककर, WHERE क्लॉज के समूह के साथ, "यहां आप हैं, सबसे अच्छा कर सकते हैं" कहने के समान थे। नए वाक्यविन्यास के साथ, क्वेरी ऑप्टिमाइज़र के पास यह जानने के लिए कम काम होता है कि कौन से हिस्से एक साथ जाते हैं।

तो आपके पास यह है।

बाएं और INNER जॉइन भविष्य की लहर है।

+21

"अधिकांश आधुनिक डेटाबेस में बहिष्कृत किया जा रहा है।" --- सिर्फ उत्सुक, कौन सा? – zerkms

+3

@zerkms अधिकांश ... –

+9

मुझे क्षमा करें, * = ऑपरेटर से परिचित नहीं हूं, यह क्या करता है? धन्यवाद! – ultrajohn

0

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

+1

मुझे जॉइन सिंटैक्स का उपयोग न करने और इसे पहली तरह से करने की आदत के साथ लाया गया था। मुझे स्वीकार करना होगा कि मैं अभी भी आदत में अक्सर अटक गया हूं क्योंकि मुझे लगता है कि मेरे दिमाग को उस तर्क का पालन करने के लिए सशर्त बनाया गया है, मुझे लगता है कि कई बार मुझे सिंटैक्स में शामिल होना मुश्किल लगता है। – TheTXI

+3

मुझे भी इस तरह सिखाया गया था। मैंने अपनी कोडिंग शैली बदल दी, क्योंकि लोग इसे देखेंगे और आसानी से पहचान नहीं पाएंगे कि क्या हो रहा था। चूंकि इसमें कोई तार्किक अंतर नहीं है और मुझे बाद में पूर्व को चुनने का कोई कारण नहीं मिल रहा है, मुझे लगा कि मुझे कोड को स्पष्ट करने के लिए अनुकूल होना चाहिए ताकि दूसरों को जो कुछ मैं लिखूं उसे समझने में मदद कर सकूं। अतिरिक्त वाक्यविन्यास के लिए – kemiller2002

0

डेटाबेस में, वे वही होते हैं। आपके लिए, हालांकि, आपको कुछ स्थितियों में उस दूसरे वाक्यविन्यास का उपयोग करना होगा। उन प्रश्नों को संपादित करने के लिए जो इसका उपयोग करने के लिए समाप्त होते हैं (पता लगाने के लिए कि आपको बाएं शामिल होने की आवश्यकता है जहां आप सीधे शामिल थे), और स्थिरता के लिए, मैं केवल दूसरी विधि पर पैटर्न चाहता हूं। यह पढ़ने के प्रश्नों को आसान बना देगा।

15

जॉइन सिंटैक्स उस तालिका के पास स्थितियां रखता है जो वे लागू होते हैं। जब आप बड़ी मात्रा में तालिकाओं में शामिल होते हैं तो यह विशेष रूप से उपयोगी होता है।

वैसे, आप एक बाहरी पहला वाक्य रचना भी साथ में शामिल होने के कर सकते हैं:

WHERE a.x = b.x(+) 

या

WHERE a.x *= b.x 

या

WHERE a.x = b.x or a.x not in (select x from b) 
+0

+1! मुझे कभी पता नहीं था कि आप ऐसा कर सकते हैं ... – JFV

+2

* = वाक्यविन्यास एमएस एसक्यूएल सर्वर में बहिष्कृत है और अच्छे कारण के लिए: न केवल इसे पढ़ने में मुश्किल बनाता है, लेकिन ऐसा नहीं करता जो लोग सोचते हैं कि यह करता है और यह है एक समान दिखने वाली बाएं जॉइन के समान नहीं। (+) वाक्यविन्यास मुझसे अपरिचित है; एसक्यूएल कार्यान्वयन क्या करता है? –

+1

अन्य वाक्यविन्यास कम से कम ओरेकल द्वारा उपयोग किया जाता है। –

0

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

2

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

ओरेकल:

SELECT a.foo, b.foo 
    FROM a, b 
WHERE a.x = b.x(+) 

MSSQLServer (हालांकि यह 2000 के संस्करण में deprecated हो गया है)/Sybase:

SELECT a.foo, b.foo 
    FROM a, b 
WHERE a.x *= b.x 

लेकिन आपके प्रश्न पर लौट रहा है। मुझे जवाब नहीं पता है, लेकिन यह शायद इस तथ्य से संबंधित है कि पर अभिव्यक्ति जोड़ने से अधिक प्राकृतिक (वाक्य रचनात्मक रूप से, कम से कम) है, जहां खंड जब आप ठीक से कर रहे हैं: में शामिल हो रहा है ।

+0

एसक्यूएल सर्वर ने बहिष्कृत किया है कि सिंटैक्स में शामिल हो गया है और यहां तक ​​कि SQL Server 2000 में भी यह लगातार परिणाम नहीं देगा (कभी-कभी यह बाएं शामिल होने के बजाय एक क्रॉस जॉइन करता है) और SQL सर्वर में कभी भी उपयोग नहीं किया जाना चाहिए। – HLGEM

+0

@ एचएलजीईएम: जानकारी के लिए धन्यवाद। मैं जो कह रहा हूं उसे प्रतिबिंबित करने के लिए मैं अपनी पोस्ट अपडेट करने जा रहा हूं। –

9

दूसरे को प्राथमिकता दी जाती है क्योंकि यह क्लोज़ में प्रवेश करने के लिए भूलकर एक आकस्मिक क्रॉस में शामिल होने की संभावना कम होती है। क्लॉज पर नो के साथ शामिल होने से सिंटैक्स चेक में असफल हो जायेगा, पुरानी शैली में शामिल नहीं होगा, जहां क्लॉज असफल नहीं होगा, यह एक क्रॉस जॉइन करेगा।

इसके अतिरिक्त जब आपको बाद में बाएं शामिल होना है, तो यह रखरखाव के लिए सहायक है कि वे सभी एक ही संरचना में हैं। और पुराना वाक्यविन्यास 1 99 2 से पुराना हो गया है, यह इसका उपयोग बंद करने के लिए पिछली बार है।

प्लस मैंने पाया है कि कई लोग जो विशेष रूप से पहले वाक्यविन्यास का उपयोग करते हैं, वास्तव में शामिल नहीं होते हैं और समझते समय सही परिणामों को प्राप्त करने के लिए जोड़ों को समझना महत्वपूर्ण होता है।

9

असल में, जब अपने FROM खंड इसलिए की तरह टेबल को सूचीबद्ध करता है:

SELECT * FROM 
    tableA, tableB, tableC 

परिणाम तालिकाओं में सभी पंक्तियों के एक क्रॉस उत्पाद है ए, बी, सी तो फिर तुम प्रतिबंध WHERE tableA.id = tableB.a_id जो फेंक होगा लागू पंक्तियों की एक बड़ी संख्या, फिर आगे ... AND tableB.id = tableC.b_id और आपको केवल उन पंक्तियों को प्राप्त करना चाहिए जिनमें आप वास्तव में रूचि रखते हैं।

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

tableA.id = tableB.a_id 
AND tableB.id = tableC.b_id 

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

5

SELECT * FROM table1, table2, ... वाक्य रचना (जरूरी नहीं एक गणितीय सटीक बयान) कठिन है और कठिन तालिकाओं की संख्या बढ़ जाती के रूप में पढ़ने के लिए टेबल के एक जोड़े के लिए ठीक है, लेकिन यह तेजी से हो जाता है।

जॉइन सिंटैक्स लिखना कठिन है (शुरुआत में), लेकिन यह स्पष्ट करता है कि कौन से मानदंडों को प्रभावित करता है। इससे गलती करना मुश्किल हो जाता है।

इसके अलावा, यदि सभी शामिल हैं INNER हैं, तो दोनों संस्करण समकक्ष हैं। हालांकि, जिस पल में आपके पास बयान में कहीं भी शामिल है, चीजें अधिक जटिल हो जाती हैं और यह वस्तुतः गारंटी देता है कि जो भी आप लिखते हैं वह आपके द्वारा लिखे गए विचारों से पूछताछ नहीं करेगा।

11

पहला तरीका पुराना मानक है। दूसरी विधि एसक्यूएल-9 2, http://en.wikipedia.org/wiki/SQL में पेश की गई थी। पूरा मानक http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt पर देखा जा सकता है।

डाटाबेस कंपनियों ने एसक्यूएल-9 2 मानक अपनाए जाने में कई सालों लगे।

इसलिए दूसरी विधि को प्राथमिकता देने का कारण यह है कि यह एएनएसआई और आईएसओ मानक समिति के अनुसार एसक्यूएल मानक है।

+0

',' अभी भी मानक है। एक बार उप-चयन शुरू किए जाने के बाद 'ऑन' को केवल 'बाहरी शामिल' के लिए पेश किया जाना आवश्यक था। – philipxy

6

मुझे लगता है कि इस पृष्ठ पर स्पष्ट विधि में दूसरी विधि को अपनाने के कुछ अच्छे कारण हैं। क्लिंचर हालांकि यह है कि जब WHERE खंड से जॉइन मानदंड हटा दिए जाते हैं तो WHERE खंड में शेष चयन मानदंडों को देखना अधिक आसान हो जाता है।

वास्तव में जटिल चयन विवरणों में पाठक के लिए यह समझना बहुत आसान हो जाता है कि क्या हो रहा है।

0
<ul id="da-thumbs" class="da-thumbs"> 
        <?php $query = mysql_query("select * from teacher_class 
        LEFT JOIN class ON class.class_id = teacher_class.class_id 
        LEFT JOIN subject ON subject.subject_id = teacher_class.subject_id 
        where teacher_id = '$session_id' and school_year = '$school_year' ")or die(mysql_error()); 
        $count = mysql_num_rows($query); 

        if ($count > 0){ 
        while($row = mysql_fetch_array($query)){ 
        $id = $row['teacher_class_id']; 

        ?> 
         <li id="del<?php echo $id; ?>"> 
          <a href="my_students.php<?php echo '?id='.$id; ?>"> 
            <img src ="../<?php echo $row['thumbnails'] ?>" width="124" height="140" class="img-polaroid" alt=""> 
           <div> 
           <span><p><?php echo $row['class_name']; ?></p></span> 
           </div> 
          </a> 
          <p class="class"><?php echo $row['class_name']; ?></p> 
          <p class="subject"><?php echo $row['subject_code']; ?></p> 
          <a href="#<?php echo $id; ?>" data-toggle="modal"><i class="icon-trash"></i> Hapus</a> 

         </li> 
        <?php include("modal_hapus_kelas.php"); ?> 
       <?php } }else{ ?> 
       <div class="alert alert-info"><i class="icon-info-sign"></i> Tidak ada kelas</div> 
       <?php } ?> 
       </ul> 
संबंधित मुद्दे