SQL EXISTS स्टेटमेंट कैसे काम करते हैं?


88

मैं SQL सीखने की कोशिश कर रहा हूं और EXISTS स्टेटमेंट को समझने में मुश्किल समय आ रहा है। मुझे "अस्तित्व" के बारे में यह उद्धरण आया और कुछ समझ में नहीं आया:

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

मुझे समझ में नहीं आ रहा है कि बाहरी क्वेरी यह कैसे जानती है कि उपकुंजी किस पंक्ति की जाँच कर रही है? उदाहरण के लिए:

SELECT *
  FROM suppliers
 WHERE EXISTS (select *
                 from orders
                where suppliers.supplier_id = orders.supplier_id);

मैं समझता हूं कि यदि आपूर्तिकर्ता और आदेश तालिका मिलान से आईडी, सबकुछ सही हो जाएगा और आपूर्तिकर्ताओं की तालिका में मिलान पंक्ति से सभी कॉलम आउटपुट हो जाएंगे। मुझे क्या नहीं मिलता है कि कैसे उपकुंजी संचार करती है कि किस विशिष्ट पंक्ति (आपूर्तिकर्ता आईडी 25 के साथ पंक्ति कहती है) को मुद्रित किया जाना चाहिए यदि केवल एक सही या गलत लौटाया जा रहा है।

यह मुझे प्रतीत होता है कि बाहरी प्रश्न और उपश्रेणी के बीच कोई संबंध नहीं है।

जवाबों:


98

इस पर इस तरीके से विचार करें:

'प्रत्येक' पंक्ति से Suppliers, जांचें कि क्या वहां मौजूद Orderतालिका में एक पंक्ति है जो स्थिति से मिलती है Suppliers.supplier_id(यह बाहरी क्वेरी वर्तमान 'पंक्ति' से आती है) = Orders.supplier_id। जब आप पहली मिलान पंक्ति पाते हैं, तो वहीं रुकें - WHERE EXISTSसंतुष्ट हो गए हैं।

बाहरी क्वेरी और सबक्वेरी के बीच की मैजिक लिंक इस तथ्य में निहित है कि Supplier_idप्रत्येक मूल्यांकन किए गए मूल्यांकन के लिए बाहरी क्वेरी से सबक्वेरी को पास किया जाता है।

या, इसे दूसरे तरीके से रखने के लिए, सबक्वेरी को बाहरी क्वेरी की प्रत्येक तालिका पंक्ति के लिए निष्पादित किया जाता है।

यह ऐसा नहीं है कि उपशम पूरे पर क्रियान्वित किया जाता है और 'सही / गलत' हो जाता है और फिर बाहरी क्वेरी के साथ इस 'सही / गलत' स्थिति का मिलान करने की कोशिश करता है।


7
धन्यवाद! "यह पूरी तरह से निष्पादित उपश्रेणी की तरह नहीं है और 'सत्य / असत्य' हो जाता है, और फिर बाहरी रूप से इस 'सही / गलत' स्थिति से मेल खाने की कोशिश करता है।" क्या वास्तव में यह मेरे लिए मंजूरी दे दी है, मैं सोच रहा हूँ कि कैसे उपश्रेणियों काम करते हैं (और कई बार वे करते हैं), लेकिन आपने जो कहा वह समझ में आता है क्योंकि उपशम बाहरी क्वेरी पर निर्भर करता है और इसलिए प्रति पंक्ति एक बार निष्पादित किया जाना चाहिए
क्लेयर लियू

32

यह मुझे प्रतीत होता है कि बाहरी प्रश्न और उपश्रेणी के बीच कोई संबंध नहीं है।

आपको क्या लगता है कि EXISTS उदाहरण के अंदर WHause क्लॉज क्या कर रहा है? आप उस नतीजे पर कैसे आते हैं जब SUPPLIERS का संदर्भ FROM में नहीं है या EXISTS क्लॉज के भीतर शामिल हैं?

TRUE / FALSE के लिए EXISTS मूल्यांकन करता है, और मानदंड के पहले मैच पर TRUE के रूप में बाहर निकलता है - यही कारण है कि यह तेजी से हो सकता है IN। यह भी जान लें कि किसी EXISTS में सेलेक्ट क्लॉज को नजरअंदाज किया जाता है - IE:

SELECT s.*
  FROM SUPPLIERS s
 WHERE EXISTS (SELECT 1/0
                 FROM ORDERS o
                WHERE o.supplier_id = s.supplier_id)

... शून्य त्रुटि से एक विभाजन मारा जाना चाहिए, लेकिन यह नहीं होगा। WHERE क्लॉज एक EXISTS क्लॉज का सबसे महत्वपूर्ण टुकड़ा है।

यह भी जान लें कि एक JOIN EXISTS का प्रत्यक्ष प्रतिस्थापन नहीं है, क्योंकि माता-पिता से जुड़े एक से अधिक बाल रिकॉर्ड होने पर डुप्लिकेट अभिभावक रिकॉर्ड होंगे।


1
मुझे अभी भी कुछ याद आ रहा है। यदि यह पहले मैच से बाहर निकलता है, तो आउटपुट सभी परिणाम कहां से समाप्त होता है, जहां o.supplierid = s.supplierid? क्या इसके बजाय यह केवल पहला परिणाम नहीं होगा?
दान

3
@ डान: EXISTSपहला मैच होने पर वापसी लौटाता है - क्योंकि आपूर्तिकर्ता ORDERS तालिका में कम से कम एक बार मौजूद होता है। यदि आप ORDERS में एक से अधिक बच्चे के संबंध होने के कारण SUPPLIER डेटा के दोहराव को देखना चाहते हैं, तो आपको एक JOIN का उपयोग करना होगा। लेकिन अधिकांश ऐसा नहीं चाहते हैं कि डुप्लिकेट और रनिंग BY BY / DISTINCT ओवरहेड को क्वेरी में जोड़ने के लिए उत्तरदायी है। SQL सर्वर पर की EXISTSतुलना में अधिक कुशल है SELECT DISTINCT ... FROM SUPPLIERS JOIN ORDERS ..., हाल ही में Oracle या MySQL पर परीक्षण नहीं किया गया है।
OMG पोंजी

मेरा एक प्रश्न था, क्या प्रत्येक रिकॉर्ड के लिए किया गया मिलान बाहरी क्वेरी में चयनित है। जैसा कि हम 5 बार आदेशों से प्राप्त करते हैं यदि आपूर्तिकर्ता से चयनित 5 पंक्तियाँ हैं।
राहुल कडुकर

24

आप या तो का उपयोग कर समान परिणाम उत्पन्न कर सकते JOIN, EXISTS, IN, या INTERSECT:

SELECT s.supplier_id
FROM suppliers s
INNER JOIN (SELECT DISTINCT o.supplier_id FROM orders o) o
    ON o.supplier_id = s.supplier_id

SELECT s.supplier_id
FROM suppliers s
WHERE EXISTS (SELECT * FROM orders o WHERE o.supplier_id = s.supplier_id)

SELECT s.supplier_id 
FROM suppliers s 
WHERE s.supplier_id IN (SELECT o.supplier_id FROM orders o)

SELECT s.supplier_id
FROM suppliers s
INTERSECT
SELECT o.supplier_id
FROM orders o

1
महान जवाब, लेकिन यह भी कि यह बेहतर है कि सहसंबंध से बचने के लिए उपयोग न करना बेहतर है
फ्लोरियन फ्रोइलिच

1
यदि आपको लगता है कि कौन सी क्वेरी तेजी से चलेगी यदि आपूर्तिकर्ताओं में 10M पंक्तियाँ हैं और आदेशों में 100M पंक्तियाँ हैं और क्यों?
तेजा

7

यदि आपके पास एक क्लॉज है जो इस तरह दिखता है:

WHERE id in (25,26,27) -- and so on

आप आसानी से समझ सकते हैं कि कुछ पंक्तियाँ क्यों लौटाई जाती हैं और कुछ नहीं हैं।

जब खंड इस तरह है:

WHERE EXISTS (select * from orders where suppliers.supplier_id = orders.supplier_id);

इसका सिर्फ यह अर्थ है: आदेश पंक्तियों में एक ही रिकॉर्ड के साथ एक ही आईडी के साथ वापसी पंक्तियाँ।


2

यह एक बहुत अच्छा सवाल है, इसलिए मैंने अपने ब्लॉग पर इस विषय के बारे में एक बहुत विस्तृत लेख लिखने का फैसला किया है ।

डेटाबेस तालिका मॉडल

मान लेते हैं कि हमारे डेटाबेस में निम्नलिखित दो टेबल हैं, जो एक से कई टेबल रिलेशनशिप बनाते हैं।

SQL EXISTS टेबल

studentतालिका अभिभावक होता है और student_gradeबच्चे को मेज है, क्योंकि यह एक student_id विदेशी कुंजी स्तंभ छात्र तालिका में आईडी प्राथमिक कुंजी स्तंभ को संदर्भित है।

student tableनिम्नलिखित दो रिकॉर्ड में शामिल हैं:

| id | first_name | last_name | admission_score |
|----|------------|-----------|-----------------|
| 1  | Alice      | Smith     | 8.95            |
| 2  | Bob        | Johnson   | 8.75            |

और, student_gradeतालिका उन ग्रेडों को संग्रहीत करती है जो छात्र प्राप्त करते हैं:

| id | class_name | grade | student_id |
|----|------------|-------|------------|
| 1  | Math       | 10    | 1          |
| 2  | Math       | 9.5   | 1          |
| 3  | Math       | 9.75  | 1          |
| 4  | Science    | 9.5   | 1          |
| 5  | Science    | 9     | 1          |
| 6  | Science    | 9.25  | 1          |
| 7  | Math       | 8.5   | 2          |
| 8  | Math       | 9.5   | 2          |
| 9  | Math       | 9     | 2          |
| 10 | Science    | 10    | 2          |
| 11 | Science    | 9.4   | 2          |

SQL EXISTS

मान लें कि हम उन सभी छात्रों को प्राप्त करना चाहते हैं, जिन्हें गणित कक्षा में 10 ग्रेड प्राप्त हुए हैं।

यदि हम केवल छात्र पहचानकर्ता में रुचि रखते हैं, तो हम इस तरह एक क्वेरी चला सकते हैं:

SELECT
    student_grade.student_id
FROM
    student_grade
WHERE
    student_grade.grade = 10 AND
    student_grade.class_name = 'Math'
ORDER BY
    student_grade.student_id

लेकिन, आवेदन studentकेवल पहचानकर्ता का पूरा नाम प्रदर्शित करने में रुचि रखता है , इसलिए हमें studentतालिका से भी जानकारी चाहिए ।

studentगणित में 10 ग्रेड वाले रिकॉर्ड को फ़िल्टर करने के लिए , हम इस तरह से EXISTS SQL ऑपरेटर का उपयोग कर सकते हैं:

SELECT
    id, first_name, last_name
FROM
    student
WHERE EXISTS (
    SELECT 1
    FROM
        student_grade
    WHERE
        student_grade.student_id = student.id AND
        student_grade.grade = 10 AND
        student_grade.class_name = 'Math'
)
ORDER BY id

ऊपर क्वेरी चलाते समय, हम देख सकते हैं कि केवल ऐलिस पंक्ति चयनित है:

| id | first_name | last_name |
|----|------------|-----------|
| 1  | Alice      | Smith     |

बाहरी क्वेरी उस studentपंक्ति कॉलम का चयन करती है जिसे हम ग्राहक को वापस करने में रुचि रखते हैं। हालाँकि, WHERE क्लॉज़ संबंधित आंतरिक उपकुंजी के साथ EXISTS ऑपरेटर का उपयोग कर रहा है।

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

आंतरिक सबक्वेरी को सहसंबद्ध किया जाता है क्योंकि student_gradeटेबल के छात्र_आईडी कॉलम को बाहरी छात्र तालिका के आईडी कॉलम से मिलान किया जाता है।


क्या शानदार जवाब है। मुझे लगता है कि मुझे अवधारणा नहीं मिली क्योंकि मैं एक गलत उदाहरण का उपयोग कर रहा था। क्या EXISTकेवल सहसंबद्ध उपश्रेणी के साथ काम करता है ? मैं क्वेरी के साथ खेल रहा था जिसमें केवल 1 तालिका थी, जैसे SELECT id FROM student WHERE EXISTS (SELECT 1 FROM student WHERE student.id > 1)। मुझे पता है कि मैंने जो लिखा था वह एक साधारण प्रश्न द्वारा प्राप्त किया जा सकता है लेकिन मैं इसका उपयोग केवल समझने के लिए कर रहा था। मुझे सारी पंक्तियाँ मिल गईं। क्या यह वास्तव में इस तथ्य के कारण है कि मैंने सहसंबंधित उप-वर्ग का उपयोग नहीं किया? धन्यवाद।
बोवेन लियू

यह केवल संबंधित उप-श्रेणियों के लिए समझ में आता है क्योंकि आप बाहरी क्वेरी के रिकॉर्ड को फ़िल्टर करना चाहते हैं। आपके मामले में आंतरिक प्रश्न को WHERE TRUE
व्लाद मिहालसीया

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

0

EXISTS का मतलब है कि सबकुछ कम से कम एक पंक्ति में वापस आ जाए, यही वास्तव में है। उस मामले में, यह एक सहसंबद्ध उपश्रेणी है क्योंकि यह बाहरी तालिका के सप्लायर_आईडी को आंतरिक तालिका के आपूर्तिकर्ता_एड को जांचता है। यह प्रश्न कहता है, वास्तव में:

सभी आपूर्तिकर्ताओं का चयन करें प्रत्येक आपूर्तिकर्ता आईडी के लिए, देखें कि क्या इस आपूर्तिकर्ता के लिए कोई आदेश मौजूद है यदि आपूर्तिकर्ता आदेश तालिका में मौजूद नहीं है, तो आपूर्तिकर्ता को उन परिणामों से हटा दें RETURN सभी आपूर्तिकर्ता जिनके पास ऑर्डर तालिका में संबंधित पंक्तियां हैं

आप इस मामले में INNER JOIN के साथ भी ऐसा कर सकते हैं।

SELECT suppliers.* 
  FROM suppliers 
 INNER 
  JOIN orders 
    ON suppliers.supplier_id = orders.supplier_id;

पोंजी टिप्पणी सही है। आपको उस जुड़ने के साथ समूहीकरण करना होगा, या आपके द्वारा आवश्यक डेटा के आधार पर अलग-अलग चयन करना होगा।


4
आंतरिक जुड़ाव EXISTS से अलग परिणाम देगा यदि एक से अधिक बच्चे का रिकॉर्ड माता-पिता के साथ जुड़ा हुआ है - वे समान नहीं हैं।
OMG पॉनीज़

मुझे लगता है कि मेरा भ्रम यह हो सकता है कि मैंने पढ़ा है कि एक उदाहरण के साथ उपश्रेणी सही या गलत है; लेकिन यह केवल एक चीज नहीं हो सकती कि वह वापस आए, है ना? क्या उपश्रेणी उन सभी "आपूर्तिकर्ताओं" को भी लौटाती है जिनके पास ऑर्डर तालिका में समान पंक्तियाँ हैं? लेकिन अगर यह है, तो EXISTS स्टेटमेंट बूलियन परिणाम कैसे दे रहा है? मैं जो कुछ भी पाठ्य पुस्तकों में पढ़ रहा हूं, वह कह रहा है कि यह केवल एक बूलियन परिणाम देता है, इसलिए मुझे कोड के परिणाम को समझने के लिए एक कठिन समय मिल रहा है, जो मुझे बताया जा रहा है।
दान

एक समारोह की तरह EXISTS पढ़ें ... EXISTS (परिणाम)। यदि परिणाम खाली है, तो EXISTS फ़ंक्शन सही है, यदि परिणाम पंक्तियाँ हैं, तो यह वापस आ जाएगी। वह मूल रूप से यह है।
डेविड

3
@Dan, विचार करें कि EXISTS () तार्किक रूप से प्रत्येक स्रोत पंक्ति के लिए स्वतंत्र रूप से मूल्यांकन किया जाता है - यह संपूर्ण क्वेरी के लिए एकल मान नहीं है।
अरवो

-1

आपके द्वारा वर्णित एक सहसंबद्ध उपश्रेणी के साथ एक तथाकथित क्वेरी है ।

(सामान्य रूप से) यह कुछ ऐसा है जिसे आपको एक जुड़ाव के बजाय क्वेरी लिखकर बचने की कोशिश करनी चाहिए:

SELECT suppliers.* 
FROM suppliers 
JOIN orders USING supplier_id
GROUP BY suppliers.supplier_id

क्योंकि अन्यथा, बाहरी क्वेरी में प्रत्येक पंक्ति के लिए सबक्वेरी निष्पादित की जाएगी।


2
वे दो समाधान समतुल्य नहीं हैं। जॉइन EXISTS सबक्वेरी की तुलना में एक अलग परिणाम देता है यदि इसमें एक से अधिक पंक्ति सम्मिलित होती है ordersजो जॉइन कंडीशन से मेल खाती है।
a_horse_with_no_name

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