SQL "का चयन करें जहां उपशम में नहीं" कोई परिणाम नहीं देता है


130

अस्वीकरण: मैंने समस्या का पता लगा लिया है (मुझे लगता है), लेकिन मैं इस मुद्दे को स्टैक ओवरफ्लो में जोड़ना चाहता था क्योंकि मैं (आसानी से) इसे कहीं भी नहीं पा सकता था। इसके अलावा, किसी के पास मेरे मुकाबले बेहतर जवाब हो सकता है।

मेरे पास एक डेटाबेस है जहां एक टेबल "कॉमन" को कई अन्य तालिकाओं द्वारा संदर्भित किया जाता है। मैं देखना चाहता था कि कॉमन टेबल में कौन से रिकॉर्ड अनाथ थे (यानी, अन्य किसी भी टेबल से कोई संदर्भ नहीं था)।

मैंने यह क्वेरी चलाई:

select *
from Common
where common_id not in (select common_id from Table1)
and common_id not in (select common_id from Table2)

मुझे पता है कि अनाथ रिकॉर्ड हैं, लेकिन कोई रिकॉर्ड वापस नहीं किया गया। क्यों नहीं?

(यह SQL सर्वर है, अगर यह मायने रखता है।)


इस stackoverflow.com/a/129152/1667619 क्यों सवाल का जवाब बहुत अच्छी तरह से।
रूचन

जवाबों:


234

अपडेट करें:

मेरे ब्लॉग के इन लेखों में विधियों के बीच अंतर के बारे में अधिक विस्तार से बताया गया है:


ऐसी क्वेरी करने के तीन तरीके हैं:

  • LEFT JOIN / IS NULL:

    SELECT  *
    FROM    common
    LEFT JOIN
            table1 t1
    ON      t1.common_id = common.common_id
    WHERE   t1.common_id IS NULL
  • NOT EXISTS:

    SELECT  *
    FROM    common
    WHERE   NOT EXISTS
            (
            SELECT  NULL
            FROM    table1 t1
            WHERE   t1.common_id = common.common_id
            )
  • NOT IN:

    SELECT  *
    FROM    common
    WHERE   common_id NOT IN
            (
            SELECT  common_id
            FROM    table1 t1
            )

कब table1.common_id यह अशक्त नहीं होता है, तो ये सभी प्रश्न शब्दार्थ समान होते हैं।

जब यह अशोभनीय होता है, तब NOT INसे अलग है, क्योंकि IN(और इसलिए, NOT IN) वापसी NULLतब होती है जब किसी सूची में कोई मान किसी चीज से मेल नहीं खाताNULL

यह भ्रामक हो सकता है लेकिन अगर हम इसके लिए वैकल्पिक वाक्यविन्यास को याद करते हैं तो यह और स्पष्ट हो सकता है:

common_id = ANY
(
SELECT  common_id
FROM    table1 t1
)

इस स्थिति का परिणाम सूची के भीतर सभी तुलनाओं का एक बूलियन उत्पाद है। बेशक, एक एकल NULLमान NULLपरिणाम देता है जो पूरे परिणाम को NULLभी प्रस्तुत करता है।

हम कभी यह निश्चित रूप से नहीं कह सकते हैं कि common_idइस सूची में से कुछ भी समान नहीं है, क्योंकि कम से कम एक मान है NULL

मान लें कि हमारे पास ये डेटा हैं:

common

--
1
3

table1

--
NULL
1
2

LEFT JOIN / IS NULLऔर NOT EXISTSलौट आएगा 3, कुछ भी नहींNOT IN लौटाएगा (क्योंकि यह हमेशा या तो मूल्यांकन करेगा )।FALSENULL

में MySQL, गैर-व्यर्थ स्तम्भ पर मामले में, LEFT JOIN / IS NULLऔर NOT INकी तुलना में एक छोटा सा (कई प्रतिशत) अधिक कुशल हैं NOT EXISTS। यदि स्तंभ अशक्त है,NOT EXISTS तो सबसे अधिक कुशल है (फिर से, ज्यादा नहीं)।

Oracleतीनों प्रश्नों में , समान योजनाएँ (a ANTI JOIN) मिलती हैं ।

में SQL Server, NOT IN/ NOT EXISTSअधिक कुशल हैं, क्योंकि इसके ऑप्टिमाइज़र द्वारा LEFT JOIN / IS NULLअनुकूलित नहीं किया जा सकता है ANTI JOIN

में PostgreSQL, LEFT JOIN / IS NULLऔर NOT EXISTSकी तुलना में अधिक कुशल हैं NOT IN, साइन वे एक के लिए अनुकूलित कर रहे हैं Anti Join, जबकि NOT INका उपयोग करता है hashed subplan(या यहां तक कि एक सादे subplanअगर सबक्वेरी हैश लिए बहुत बड़ी है)


8
बहुत बढ़िया जवाब! धन्यवाद!
StevenMcD

यह कमाल है और बहुत उपयोगी है
kavun

1
+1 क्योंकि, साढ़े चार साल, इस जवाब ने मुझे एक समस्या से उबारने में मदद की, जिसने मुझे स्टंप किया था!
कार्सन 63000

@ Carson63000 स्नैप! मुझे लगा कि मैं इस जवाब को देखने से पहले पागल हो रहा था
बॉबी

1
@IstiaqueAhmed: NOT EXISTSTRUE का मूल्यांकन करता है यदि इसके अंदर की क्वेरी किसी भी पंक्तियों को वापस करती है। SELECT NULLके रूप में अच्छी तरह से SELECT *या SELECT 1या कुछ और हो सकता है, NOT EXISTSविधेय पंक्तियों के मूल्यों को नहीं देखता है, केवल उन्हें गिनता है।
क्वासोनि

36

यदि आप चाहते हैं कि दुनिया एक दो-मूल्यवान बूलियन स्थान हो, तो आपको अपने आप को अशक्त (तीसरे मूल्य) मामले को रोकना होगा।

उस सूची में मत लिखो जो सूची पक्ष में अशक्तता की अनुमति देती है। उन्हें फ़िल्टर करें!

common_id not in
(
  select common_id from Table1
  where common_id is not null
)

6
इन-क्लॉज-लिस्ट में मौजूद नल गायब क्वेरी परिणामों के लिए एक सामान्य कारण है।
एमी बी

'जब एक अशक्त के साथ तुलना की जाती है, तो उत्तर अज्ञात होता है' - @ जेरेमी स्टीन द्वारा उत्तर से। से common_id not in, हम अभी भी common_idमान सकते हैं NULL। तो क्या कोई परिणाम नहीं मिलने की समस्या अभी भी कायम है?
इस्तियाक अहमद

5

Table1 या Table2 में common_id के लिए कुछ अशक्त मूल्य हैं। इसके बजाय इस क्वेरी का उपयोग करें:

select *
from Common
where common_id not in (select common_id from Table1 where common_id is not null)
and common_id not in (select common_id from Table2 where common_id is not null)

1
क्या होगा अगर एक तालिका में डेटा है लेकिन दूसरे में नहीं है? क्या आप "और" या "या" वहां चाहते हैं?
फिलिप केली

1
मैं किसी भी तालिका में संदर्भित नहीं रिकॉर्ड की तलाश कर रहा हूं, इसलिए मैं चाहता हूं और। मैं प्रश्न स्पष्ट करूँगा।
जेरेमी स्टीन

4
select *
from Common c
where not exists (select t1.commonid from table1 t1 where t1.commonid = c.commonid)
and not exists (select t2.commonid from table2 t2 where t2.commonid = c.commonid)

4

बस मेरे सिर के ऊपर से ...

select c.commonID, t1.commonID, t2.commonID
from Common c
     left outer join Table1 t1 on t1.commonID = c.commonID
     left outer join Table2 t2 on t2.commonID = c.commonID
where t1.commonID is null 
     and t2.commonID is null

मैंने कुछ परीक्षण चलाए और यहाँ मेरे परिणाम @ patmortech का उत्तर और @ rexem की टिप्पणियां थीं।

यदि या तो Table1 या Table2 को आम तौर पर अनुक्रमित नहीं किया जाता है, तो आपको एक टेबल स्कैन मिल जाता है, लेकिन @ patmortech की क्वेरी अभी भी दोगुनी है (100K पंक्ति मास्टर तालिका के लिए)।

यदि न तो सामान्य पर अनुक्रमित किया जाता है, तो आपको दो टेबल स्कैन मिलते हैं और अंतर नगण्य है।

यदि दोनों को सामान्य रूप से अनुक्रमित किया जाता है, तो "मौजूद नहीं है" क्वेरी 1/3 समय में चलती है।


1
यह एक और जहां खंड में होना चाहिए। अन्यथा, वह काम करता है।
जेरेमी स्टीन

1
आपकी टिप्पणी के अनुसार बदला गया। "या" या तो तालिका में अनाथों को बाहर निकालता है।
ऑस्टिन सलोनन

1
वह बेहतर है। वैसे, क्या कोई कारण है कि मुझे उपकुंजी के बजाय बाहरी जोड़ों का उपयोग करना चाहिए?
जेरेमी स्टीन

3
पठनीयता प्राथमिक है। मुझे संदेह है कि एक बेहतर निष्पादन योजना उत्पन्न होगी लेकिन एक क्वेरी योजना के बिना, मैं पुष्टि नहीं कर सकता।
ऑस्टिन सलोनन 16

2
यह दृष्टिकोण बदतर है कि EXISTS का उपयोग नहीं कर रहा है - इसके परिणामस्वरूप आवश्यकता से अधिक पंक्तियों को लाने में परिणाम सम्मिलित करें, फिर स्तंभों की तुलना में परिणाम सुस्त हैं। और बूट के लिए अधिक पठनीय नहीं है।
OMG पॉनीज

3
SELECT T.common_id
  FROM Common T
       LEFT JOIN Table1 T1 ON T.common_id = T1.common_id
       LEFT JOIN Table2 T2 ON T.common_id = T2.common_id
 WHERE T1.common_id IS NULL
   AND T2.common_id IS NULL

1
यह दृष्टिकोण बदतर है कि EXISTS का उपयोग नहीं कर रहा है - इसके परिणामस्वरूप आवश्यकता से अधिक पंक्तियों को लाने में परिणाम सम्मिलित करें, फिर स्तंभों की तुलना में परिणाम सुस्त हैं। यह काम करता है, लेकिन प्रदर्शन उतना अच्छा नहीं होगा - संभवतः इससे भी बदतर, जिसमें सहसंबद्ध उपश्रेणियों का उपयोग किया जाता है।
OMG पॉनीज

3

मान लीजिए कि ये मान common_id के लिए हैं:

Common - 1
Table1 - 2
Table2 - 3, null

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

उन मूल्यों के साथ, क्वेरी इसके बराबर है:

select *
from Common
where 1 not in (2)
and 1 not in (3, null)

इसके बराबर है:

select *
from Common
where not (1=2)
and not (1=3 or 1=null)

यहीं से समस्या शुरू होती है। एक अशक्त के साथ तुलना करते समय, उत्तर अज्ञात है । तो क्वेरी कम हो जाती है

select *
from Common
where not (false)
and not (false or unkown)

गलत या अज्ञात अज्ञात है:

select *
from Common
where true
and not (unknown)

सच है और अनकाउन्ट भी नहीं है:

select *
from Common
where unknown

जहां स्थिति रिकॉर्ड वापस नहीं करती है जहां परिणाम अनकाउन्टेड है, इसलिए हमें कोई रिकॉर्ड वापस नहीं मिलता है।

इससे निपटने का एक तरीका यह है कि मौजूद ऑपरेटर का इस्तेमाल करना चाहिए बजाय इसके कि कभी भी एक्स्टॉन्स्ट वापस न आए क्योंकि यह कॉलम के बजाय पंक्तियों पर काम करता है। (एक पंक्ति या तो मौजूद है या यह नहीं है; पंक्ति स्तर पर कोई भी अशक्त अस्पष्टता नहीं है!)

select *
from Common
where not exists (select common_id from Table1 where common_id = Common.common_id)
and not exists (select common_id from Table2 where common_id = Common.common_id)

2

यह मेरे लिए काम किया :)

आम से * का चयन करें

कहाँ पे

आम_आईडी तालिका 1 से नहीं (ISNULL का चयन करें (common_id, 'dummy-data' )

और सामान्य नहीं है (तालिका 2 से ISNULL (सामान्य_id, 'डमी-डेटा' का चयन करें )


@marlar, उप-प्रश्न हमेशा 1 या 0 वापस करते हैं, मूल्यों की सूची नहीं। तो NOT INवहां कैसा प्रदर्शन होगा?
इस्तियाक अहमद


0

मेरे पास एक उदाहरण था जहां मैं देख रहा था और क्योंकि एक तालिका ने मूल्य को एक डबल के रूप में रखा था, दूसरे को एक स्ट्रिंग के रूप में, वे मैच नहीं करेंगे (या कलाकारों के बिना मेल नहीं खाते)। लेकिन केवल IN में नहीं । जैसा कि चयन ... में ... काम किया। अजीब है, लेकिन मैंने सोचा कि अगर कोई और इस साधारण फिक्स का सामना करता है तो मैं साझा करूंगा।


0

उपरोक्त विषय को समझने के लिए कृपया नीचे दिए गए उदाहरण का अनुसरण करें:

इसके अलावा आप एंटी जुड़ने के लिए निम्न लिंक पर जा सकते हैं

select department_name,department_id from hr.departments dep
where not exists 
    (select 1 from hr.employees emp
    where emp.department_id=dep.department_id
    )
order by dep.department_name;
DEPARTMENT_NAME DEPARTMENT_ID
Benefits    160
Construction    180
Contracting 190
.......

लेकिन अगर हम NOT INउस स्थिति में उपयोग करते हैं तो हमें कोई डेटा नहीं मिलता है।

select Department_name,department_id from hr.departments dep 
where department_id not in (select department_id from hr.employees );

कोई डेटा नहीं मिला

ऐसा हो रहा है ( select department_id from hr.employees) एक शून्य मान लौटा रहा है और संपूर्ण क्वेरी का मूल्यांकन गलत है। हम इसे देख सकते हैं यदि हम नीचे SQL को थोड़ा बदलते हैं और NVL फ़ंक्शन के साथ अशक्त मानों को संभालते हैं।

select Department_name,department_id from hr.departments dep 
where department_id not in (select NVL(department_id,0) from hr.employees )

अब हम डेटा प्राप्त कर रहे हैं:

DEPARTMENT_NAME DEPARTMENT_ID
Treasury    120
Corporate Tax   130
Control And Credit  140
Shareholder Services    150
Benefits    160
....

फिर से हमें डेटा मिल रहा है क्योंकि हमने एनवीएल फ़ंक्शन के साथ शून्य मान को संभाला है।


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