2009-08-31 11 views
11

नीचे दिए गए एक चुनिंदा कथन को लिखने का सबसे प्रभावी तरीका क्या है।उपरोक्त में "नहीं" के साथ एक चयन कथन लिखने का सबसे प्रभावी तरीका क्या है?

SELECT * 
FROM Orders 
WHERE Orders.Order_ID not in (Select Order_ID FROM HeldOrders) 

यह है कि जब आप किसी अन्य तालिका में नहीं हैं तो आप एक टेबल से रिकॉर्ड चाहते हैं।

+5

सबसे अच्छा तरीका विभिन्न दृष्टिकोणों को आजमाने और निष्पादन योजनाओं की जांच करना है। – pjp

+0

मेरी स्थिति में SQL Server 2000, प्रश्न में तालिकाओं पर इंडेक्स दिए गए "जॉइन" क्वेरी सबसे तेज थी। चयन * ऑर्डर से बाएं जॉइन हेल्डऑर्डर्स ओ ओ.ऑर्डर_आईडी = एच.ऑर्डर_आईडी और एच। ऑर्डर_आईडी शून्य – Stimy

उत्तर

7

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

स्थिति के आधार पर आप जो चाहते हैं उसे पूरा करने के लिए आमतौर पर तीन तरीकों का उपयोग करते हैं।

1. ऑर्डर्स.ऑर्डर_आईडी अनुक्रमित होने पर आपका उदाहरण ठीक काम करता है, और हेल्डऑर्डर काफी छोटा है।

2. एक अन्य विधि

SELECT * 
FROM Orders o 
WHERE Orders.Order_ID not in (Select Order_ID 
           FROM HeldOrders h 
           where h.order_id = o.order_id) 

नोट जहां खंड के अलावा "सहसंबद्ध सबक्वेरी" जो तुम्हारे पास क्या है की एक मामूली बदलाव है ...। हेल्डऑर्डर्स की बड़ी संख्या में पंक्तियां होने पर यह बेहतर काम करता है। ऑर्डर_आईडी को दोनों टेबलों में अनुक्रमित करने की आवश्यकता है।

3. एक अन्य विधि मैं कभी कभी का उपयोग बाहरी में शामिल होने के लिए छोड़ दिया है ...

SELECT * 
FROM Orders o 
left outer join HeldOrders h on h.order_id = o.order_id 
where h.order_id is null 

बाईं बाहरी का उपयोग करते समय शामिल होने, h.order_id एक मूल्य में यह o.order_id मिलान होगा नहीं है जब एक मिलान पंक्ति। यदि कोई मिलान पंक्ति नहीं है, तो h.order_id पूर्ण होगा। उस नल में नल मानों की जांच करके जहां आप किसी भी मैच पर फ़िल्टर नहीं कर सकते हैं।

इनमें से प्रत्येक भिन्नता विभिन्न परिदृश्यों में कम या ज्यादा कुशलता से काम कर सकती है।

+0

'@ डेव': विधि' 2' में 'EXISTS' के बजाय आप' IN IN' क्यों उपयोग करते हैं? – Quassnoi

+1

@Quassnoi: ईमानदारी से, शायद एक बुरी आदत। ऊपर दिए गए उत्तर को पढ़ने के बाद मैं EXISTS का उपयोग शुरू करने की योजना बना रहा हूं। –

+0

विकल्प 3 ने मेरे परिदृश्य में सबसे अच्छा काम किया (एसक्यूएल सर्वर 2000 ने मेरी टेबल इंडेक्स दी)। मुझे लगता है कि सबसे अच्छा जवाब कई तरीकों का परीक्षण करना है। – Stimy

4

आप LEFT OUTER JOIN का उपयोग कर सकते हैं और सही तालिका पर NULL का उपयोग कर सकते हैं।

SELECT O1.* 
FROM Orders O1 
LEFT OUTER JOIN HeldOrders O2 
ON O1.Order_ID = O2.Order_Id 
WHERE O2.Order_Id IS NULL 
+1

यह * सबसे * सबसे प्रभावी विधि होने से दूर है। – Quassnoi

+0

यह आवश्यक रूप से सबसे प्रभावी विधि नहीं होने वाला है। –

+0

यह सब-क्वेरी से काफी अधिक प्रभावशाली है, हालांकि - कम से कम यह केवल एक बार/पंक्ति के बजाय दूसरी तालिका के विरुद्ध निष्पादित करता है। – SqlRyan

19
शुरुआत के लिए

, एक (और अन्य प्रणालियों में) कैसे NOT IN विधेय SQL Server में काम करता है पर अपने ब्लॉग में एक पुराने लेख के लिए लिंक:


आप इसे निम्नानुसार लिख सकते हैं:

SELECT * 
FROM Orders o 
WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM HeldOrders ho 
     WHERE ho.OrderID = o.OrderID 
     ) 

, हालांकि, अधिकांश डेटाबेस इन प्रश्नों का इलाज करेंगे।

ये दोनों प्रश्न ANTI JOIN किसी प्रकार का उपयोग करेंगे। ,

SELECT * 
FROM Orders o 
WHERE (col1, col2) NOT IN 
     (
     SELECT col1, col2 
     FROM HeldOrders ho 
     ) 

नोट तथापि, NOT IN मुश्किल हो सकता है कि जिस तरीके के लिए यह NULL व्यवहार करता है:

यह आप इस वाक्य रचना का समर्थन नहीं करता दो या अधिक स्तंभों की जाँच करना चाहते हैं SQL Server के बाद से, SQL Server के लिए उपयोगी है मान।

हैं Held.Orders व्यर्थ है, कोई रिकॉर्ड पाया जाता है और सबक्वेरी रिटर्न लेकिन एक भी NULL, पूरे क्वेरी कुछ भी नहीं (दोनों IN और NOT IN इस मामले में NULL करने का मूल्यांकन करेंगे) वापस आ जाएगी।

Orders: 

OrderID 
--- 
1 

HeldOrders: 

OrderID 
--- 
2 
NULL 

इस क्वेरी:

SELECT * 
FROM Orders o 
WHERE OrderID NOT IN 
     (
     SELECT OrderID 
     FROM HeldOrders ho 
     ) 

कुछ भी नहीं, जो शायद नहीं है कि तुम क्या उम्मीद थी वापस आ जाएगी

इन आंकड़ों पर विचार करें।

बहरहाल, यह एक:

SELECT * 
FROM Orders o 
WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM HeldOrders ho 
     WHERE ho.OrderID = o.OrderID 
     ) 

OrderID = 1 साथ पंक्ति वापस आ जाएगी।

ध्यान दें कि LEFT JOIN दूसरों द्वारा प्रस्तावित समाधान सबसे कुशल समाधान होने से बहुत दूर हैं।

इस क्वेरी:

SELECT * 
FROM Orders o 
LEFT JOIN 
     HeldOrders ho 
ON  ho.OrderID = o.OrderID 
WHERE ho.OrderID IS NULL 

एक फिल्टर शर्त यह है कि मूल्यांकन करने और सभी को फ़िल्टर पंक्तियों जो numerius हो सकता है मिलान करने की आवश्यकता होगी का उपयोग करेगा

दोनों IN और EXISTS द्वारा इस्तेमाल किया एक ANTI JOIN विधि होगा बस यह सुनिश्चित करने की आवश्यकता है कि में प्रत्येक पंक्ति के प्रति एक बार मौजूद नहीं है, इसलिए यह पहले सभी संभावित डुप्लीकेट को खत्म कर देगा:

  • NESTED LOOPS ANTI JOIN और MERGE ANTI JOIN बस जब HeldOrders का मूल्यांकन डुप्लिकेट को छोड़ देगा।
  • HASH ANTI JOIN हैश तालिका बनाते समय डुप्लिकेट को खत्म कर देगा।
+1

पहली बार मैंने एक सहसंबंधित सबक्वायरी देखी है जिसे वास्तव में एक सहसंबंधित सबक्वायरी होने की आवश्यकता है जिसे मैं 5 मिनट से भी कम समय में ग्रोक कर सकता हूं। इच्छा है कि मैं इस चाल * साल * पहले जाना चाहता था। –

+0

'@ फिलिप केली ': कौन सा चाल ठीक है? – Quassnoi

+0

इस खंड में आपका क्या अर्थ है: "यह SQL सर्वर के लिए उपयोगी है यदि आप दो या अधिक स्तंभों को देखना चाहते हैं, क्योंकि SQL सर्वर इस वाक्यविन्यास का समर्थन नहीं करता है:"। क्या आप कह रहे हैं कि यह SQL सर्वर पर लागू नहीं होता है? क्या आप "नहीं" खो रहे हैं? – Stimy

1

मुझे यकीन है कि सबसे कारगर है क्या नहीं कर रहा हूँ, लेकिन अन्य विकल्प हैं:

1. Use EXISTS 

SELECT * 
FROM ORDERS O 
WHERE NOT EXISTS (SELECT 1 
        FROM HeldOrders HO 
        WHERE O.Order_ID = HO.OrderID) 

2. Use EXCEPT 

SELECT O.Order_ID 
FROM ORDERS O 
EXCEPT 
SELECT HO.Order_ID 
FROM HeldOrders 
0

SELECT * 
FROM Orders 
LEFT JOIN HeldOrders 
ON HeldOrders.Order_ID = Orders.Order_ID 
WHERE HeldOrders.Order_ID IS NULL 
संबंधित मुद्दे