SQL WHERE .. क्लॉज में कई कॉलम


173

मुझे SQL सर्वर में निम्नलिखित क्वेरी को लागू करने की आवश्यकता है:

select *
from table1
WHERE  (CM_PLAN_ID,Individual_ID)
IN
(
 Select CM_PLAN_ID, Individual_ID
 From CRM_VCM_CURRENT_LEAD_STATUS
 Where Lead_Key = :_Lead_Key
)

लेकिन WHERE..IN क्लॉज केवल 1 कॉलम की अनुमति देता है। मैं दूसरे आंतरिक चयन के साथ 2 या अधिक कॉलम की तुलना कैसे कर सकता हूं?


मैंने प्रासंगिक समाधानों का अवलोकन प्रदान करने की कोशिश की, यहाँ की
परिचयात्मक सावधानी के साथ

जवाबों:


110

आप उप-तालिका से एक व्युत्पन्न तालिका बना सकते हैं, और तालिका 1 से इस व्युत्पन्न तालिका में शामिल हो सकते हैं:

select * from table1 LEFT JOIN 
(
   Select CM_PLAN_ID, Individual_ID
   From CRM_VCM_CURRENT_LEAD_STATUS
   Where Lead_Key = :_Lead_Key
) table2
ON 
   table1.CM_PLAN_ID=table2.CM_PLAN_ID
   AND table1.Individual=table2.Individual
WHERE table2.CM_PLAN_ID IS NOT NULL

7
या अधिक आम तौर पर चयन करें * तालिका से अन्य में शामिल होने पर तालिका (x.x = otherTable.a और table.y = otherTable.b)
ala

4
यदि तालिका 2 तालिका 1 का बच्चा है, तो कई पंक्तियों के बारे में क्या होगा? और क्यों बाईं ओर?
gbn

1
हाँ, INNER JOIN यहाँ अधिक प्रदर्शनकारी होगा। एक बाईं ओर कर रहा है और तालिका 2 से नल को छानने का काम सिर्फ एक क्रिया तरीका है एक INNER JOIN का उपयोग करने के लिए
Pstr

गलत, यह पंक्ति को कई बार वितरित करता है, यह मानते हुए कि शामिल की गई तालिका को कई बार जोड़ा जा सकता है ... अन्यथा, एक आंतरिक जुड़ाव करें और आप अपने आप को जहाँ भी छोड़ सकते हैं।
स्टीफन स्टीगर

123

आप इसके बजाय WHIS EXISTS सिंटैक्स का उपयोग करना चाहते हैं।

SELECT *
FROM table1
WHERE EXISTS (SELECT *
              FROM table2
              WHERE Lead_Key = @Lead_Key
                        AND table1.CM_PLAN_ID = table2.CM_PLAN_ID
                        AND table1.Individual_ID = table2.Individual_ID)

5
जबकि यह काम करेगा, यह प्रश्न में असंबद्ध क्वेरी को सहसंबद्ध क्वेरी में परिवर्तित करता है। जब तक क्वेरी ऑप्टिमाइज़र चालाक नहीं है, यह आपको O (n ^ 2) प्रदर्शन दे सकता है :-( लेकिन शायद मैं ऑप्टिमाइज़र को कम कर रहा हूं ...
7:16 पर Sleske

1
मैं इस मुद्दे के बिना हर समय वाक्यविन्यास का उपयोग करता हूं। जब तक आप एक पुराने ऑप्टिमाइज़र (6.5, 7, 8, आदि) का उपयोग कर रहे हैं, तब तक इस सिंटैक्स के साथ समस्या नहीं होनी चाहिए।
मर्डनी

1
@ साल्सके: EXISTS अब तक बेहतर है: मेरे जवाब में मेरी टिप्पणी देखें। और पहले इसका परीक्षण करें,। @ मर्डेनी: मैंने पहले आपके जवाब को गलत बताया, मैं EXISTS का भी इस्तेमाल करूंगा
gbn

6
यह सबसे कुशल है, +1। प्रदर्शन तुलना के लिए मेरे ब्लॉग में इस लेख को देखें: explainextended.com/2009/06/17/efficient-exists
Quassnoi

1
यहां तक ​​कि SQL 2000 क्वेरी को O (n ^ 2) में बदले बिना अधिकांश सहसंबद्ध उपश्रेणियों को संभाल सकता है। 6.5 पर समस्या हो सकती है।
गिलामनस्टर

14

समाधान के बारे में चेतावनी:

यदि कोई गलत नहीं है, तो कई मामलों में जाँच के नतीजे मिलेंगे

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

समस्या निवारण के बारे में चेतावनी:

कई रंगों के साथ, ऐसा नहीं है कि, आप क्या चाहते हैं

जब मैं दो कॉलम के साथ एक देखता हूं, तो मैं इसका मतलब दो चीजों से कर सकता हूं:

  1. कॉलम ए और कॉलम बी का मूल्य स्वतंत्र रूप से दूसरी तालिका में दिखाई देता है
  2. कॉलम ए और कॉलम बी के मूल्य एक ही पंक्ति में दूसरी तालिका में दिखाई देते हैं

परिदृश्य 1 काफी तुच्छ है, बस दो IN कथनों का उपयोग करें।

अधिकांश मौजूदा उत्तरों के साथ, मैं यहां परिदृश्य 2 और (संक्षिप्त निर्णय) के लिए उल्लिखित और अतिरिक्त तरीकों का अवलोकन प्रदान करता हूं:

EXISTS (सुरक्षित, SQL सर्वर के लिए अनुशंसित)

जैसा कि @mrdenny द्वारा दिया गया है, EXISTS बिल्कुल वही लगता है जो आप देख रहे हैं, यहाँ उसका उदाहरण है:

SELECT * FROM T1
WHERE EXISTS
(SELECT * FROM T2 
 WHERE T1.a=T2.a and T1.b=T2.b)

बायाँ सामी जॉय (सुरक्षित, इसका समर्थन करने वाली बोलियों के लिए अनुशंसित)

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

SELECT * FROM T1
LEFT SEMI JOIN T2 ON T1.a=T2.a and T1.b=T2.b

एकाधिक कथन (सुरक्षित, लेकिन कोड दोहराव से सावधान रहें)

जैसा कि @ इन स्टेटमेंट्स में दो स्टेटमेंट्स का उपयोग करके @cataclysm द्वारा उल्लेख किया गया है, शायद यह अन्य समाधानों को बेहतर बनाएगा। हालाँकि, आपको जो कोड के साथ बहुत सावधानी बरतनी चाहिए। यदि आप कभी भी किसी भिन्न तालिका से चयन करना चाहते हैं, या जहां कथन को बदलना चाहते हैं, तो यह एक बढ़ा हुआ जोखिम है जो आप अपने तर्क में असंगति पैदा करते हैं।

मूल समाधान

SELECT * from T1
WHERE a IN (SELECT a FROM T2 WHERE something)
AND b IN (SELECT b FROM T2 WHERE something)

कोड दोहराव के बिना समाधान (मेरा मानना ​​है कि यह नियमित SQL सर्वर प्रश्नों में काम नहीं करता है)

WITH mytmp AS (SELECT a, b FROM T2 WHERE something);
SELECT * from T1 
WHERE a IN (SELECT a FROM mytmp)
AND b IN (SELECT b FROM mytmp)

ININ JOIN (तकनीकी रूप से इसे सुरक्षित बनाया जा सकता है, लेकिन अक्सर ऐसा नहीं किया जाता है)

कारण है कि मैं एक फिल्टर के रूप में एक आंतरिक जुड़ाव का उपयोग करने की अनुशंसा नहीं करता हूं, ऐसा इसलिए है क्योंकि व्यवहार में लोग अक्सर सही तालिका में डुप्लिकेट को बाईं तालिका में डुप्लिकेट का कारण बनाते हैं। और फिर मामले को बदतर बनाने के लिए, वे कभी-कभी अंतिम परिणाम को अलग बनाते हैं जबकि बाईं तालिका वास्तव में अद्वितीय (या आपके द्वारा चुने गए स्तंभों में अद्वितीय नहीं) होने की आवश्यकता नहीं हो सकती है। Futhermore यह आपको वास्तव में एक स्तंभ का चयन करने का मौका देता है जो बाईं तालिका में मौजूद नहीं है।

SELECT T1.* FROM T1
INNER JOIN 
(SELECT DISTINCT a, b FROM T2) AS T2sub
ON T1.a=T2sub.a AND T1.b=T2sub.b

सबसे आम गलतियाँ:

  1. टी 2 पर सीधे जुड़ना, एक सुरक्षित उपकुंजी के बिना। नकल के जोखिम में परिणाम)
  2. चुनें * (T2 से कॉलम प्राप्त करने के लिए प्रेरित किया गया)
  3. सेलेक्ट सी (यह गारंटी नहीं देता है कि आपका कॉलम आता है और हमेशा T1 से आएगा)
  4. कोई DISTINCT या DISTINCT गलत जगह पर नहीं है

सेपरेटर के साथ रंग का संयोजन (बहुत सुरक्षित नहीं, भयानक प्रदर्शन)

कार्यात्मक समस्या यह है कि यदि आप एक विभाजक का उपयोग करते हैं जो एक कॉलम में हो सकता है, तो यह सुनिश्चित करने के लिए मुश्किल हो जाता है कि परिणाम 100% सटीक है। तकनीकी समस्या यह है कि यह विधि अक्सर प्रकार के रूपांतरणों को उकसाती है और अनुक्रमणिका को पूरी तरह से अनदेखा करती है, जिसके परिणामस्वरूप संभवतः भयानक प्रदर्शन होता है। इन समस्याओं के बावजूद, मुझे यह स्वीकार करना होगा कि मैं कभी-कभी छोटे डेटासेट पर तदर्थ प्रश्नों के लिए भी इसका उपयोग करता हूं।

SELECT * FROM T1
WHERE CONCAT(a,"_",b) IN 
(SELECT CONCAT(a,"_",b) FROM T2)

ध्यान दें कि यदि आपके कॉलम संख्यात्मक हैं, तो कुछ SQL बोलियों के लिए आपको उन्हें पहले तार पर ले जाना होगा। मेरा मानना ​​है कि SQL सर्वर स्वचालित रूप से ऐसा करेगा।


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


13
select * from tab1 where (col1,col2) in (select col1,col2 from tab2)

नोट:
Oracle उन पंक्तियों को अनदेखा करता है जहाँ चयनित कॉलमों में से एक या अधिक NULL है। इन मामलों में आप शायद का उपयोग करना चाहते हैं NVL (कि मूल्यों में नहीं होना चाहिए) एक विशेष मूल्य के लिए शून्य मैप करने के लिए -Funktion;

select * from tab1
where (col1, NVL(col2, '---') in (select col1, NVL(col2, '---') from tab2)

2
पोस्टग्रैज सपोर्ट करता है where (colA,colB) in (... some list of tuples...)लेकिन मुझे यकीन नहीं है कि अन्य डेटाबेस भी ऐसा ही करते हैं। मैं जानना चाहूंगा।
मैक्स मर्फी

2
यह सिंटैक्स ओरेकल और डीबी 2/400 के साथ-साथ (शायद डीबी 2, भी) में समर्थित है। विश एसक्यूएल सर्वर ने इसका समर्थन किया।
क्रेजीइवन

DB2 इसका समर्थन करता है।
टेलमो Marques

यहां तक ​​कि SQLite भी इसका समर्थन करता है।
होल्गर जेकब्स

13

एक साधारण EXISTS क्लॉज सबसे साफ है

select *
from table1 t1
WHERE
EXISTS
(
 Select * --or 1. No difference...
 From CRM_VCM_CURRENT_LEAD_STATUS Ex
 Where Lead_Key = :_Lead_Key
-- correlation here...
AND
t1.CM_PLAN_ID = Ex.CM_PLAN_ID AND t1.CM_PLAN_ID =  Ex.Individual_ID
)

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

SELECT *एक JOIN के साथ नोट में पंक्ति को तालिकाओं से स्तंभ भी शामिल किया जाएगा


2

जब आप सिर्फ एक सामान्य आंतरिक जुड़ाव कर सकते हैं, तो ऐसे उदाहरणों का उपयोग क्यों करें

SELECT t.*
FROM table1 t
INNER JOIN CRM_VCM_CURRENT_LEAD_STATUS s
    ON t.CM_PLAN_ID = s.CM_PLAN_ID
    AND t.Individual_ID = s.Individual_ID
WHERE s.Lead_Key = :_Lead_Key

यदि स्थिति तालिका में (CM_PLAN_ID, Individual_ID) की जोड़ी अद्वितीय नहीं है, तो आपको इसके बजाय SELECT DISTINCT t। * की आवश्यकता हो सकती है।


3
और DISTINCT का आमतौर पर मतलब होता है एक EXISTS अधिक कुशल है
gbb

0
Postgres SQL  : version 9.6
Total records on tables : mjr_agent = 145, mjr_transaction_item = 91800

1. के साथ प्रयोग EXISTS[औसत क्वेरी समय: 1.42 s]

SELECT count(txi.id) 
FROM 
mjr_transaction_item txi
WHERE 
EXISTS ( SELECT 1 FROM mjr_agent agnt WHERE agnt.agent_group = 0 AND (txi.src_id = agnt.code OR txi.dest_id = agnt.code) ) 

2. दो लाइनों के साथ प्रयोग INक्लॉज [औसत क्वेरी समय: 0.37]

SELECT count(txi.id) FROM mjr_transaction_item txi
WHERE 
txi.src_id IN ( SELECT agnt.code FROM mjr_agent agnt WHERE agnt.agent_group = 0 ) 
OR txi.dest_id IN ( SELECT agnt.code FROM mjr_agent agnt WHERE agnt.agent_group = 0 )

3. INNNER JOINपैटर्न के साथ उपयोग [औसत क्वेरी समय: 2.9]

SELECT count(DISTINCT(txi.id)) FROM mjr_transaction_item txi
INNER JOIN mjr_agent agnt ON agnt.code = txi.src_id OR agnt.code = txi.dest_id
WHERE 
agnt.agent_group = 0

इसलिए, मैंने दूसरा विकल्प चुना।


भविष्य के पाठकों के लिए चेतावनी: प्रश्न के अनुरूप, आप शायद ANDबयानों के बजाय बयानों का उपयोग करना चाहेंगे OR
डेनिस जहरुद्दीन

@DennisJaheruddin .. आपकी टिप्पणी के लिए धन्यवाद और आपके उत्तर की बहुत अच्छी विस्तार से व्याख्या। आप सही हैं, ORकथन शायद दोहराव बढ़ाता है। मेरे मामले में, ऐसी कोई पंक्तियाँ नहीं हैं जिनमें एक ही src_idऔर dest_idएक ही पंक्ति में हो। इसलिए, मेरे मामले में दोहराव नहीं होगा।
प्रलय


-2

यदि आप एक तालिका चाहते हैं, तो निम्नलिखित क्वेरी का उपयोग करें

SELECT S.* 
FROM Student_info S
  INNER JOIN Student_info UT
    ON S.id = UT.id
    AND S.studentName = UT.studentName
where S.id in (1,2) and S.studentName in ('a','b')

और तालिका डेटा का पालन करें

id|name|adde|city
1   a   ad  ca
2   b   bd  bd
3   a   ad  ad
4   b   bd  bd
5   c   cd  cd

फिर उत्पादन के रूप में पालन करें

id|name|adde|city
1   a   ad  ca
2   b   bd  bd

id in (1,2) and studentName in ('a','b')पूरी तरह से के रूप में नहीं है (id, studentName) in ((1,'a'),(2,'b'))। आईडी = 2 और नाम = 'ए' वाले रिकॉर्ड के बारे में सोचें। बेशक, अगर आईडी अद्वितीय है, तो प्रभाव कम हो जाता है, लेकिन फिर, अगर आईडी अद्वितीय है, तो हमें नामों से अधिक फ़िल्टर करने की आवश्यकता नहीं है।
quetzalcoatl

-2

हम बस यह कर सकते हैं।

   select *
   from 
    table1 t, CRM_VCM_CURRENT_LEAD_STATUS c
    WHERE  t.CM_PLAN_ID = c.CRM_VCM_CURRENT_LEAD_STATUS
    and t.Individual_ID = c.Individual_ID

-2

किसी रूप में स्तंभों को एक साथ जोड़ना एक "हैक" है, लेकिन जब उत्पाद एक से अधिक स्तंभों के लिए अर्ध-जोड़ों का समर्थन नहीं करता है, तो कभी-कभी आपके पास कोई विकल्प नहीं होता है।

उदाहरण जहां आंतरिक / बाहरी जुड़ने के समाधान से काम नहीं चलेगा:

select * from T1 
 where <boolean expression>
   and (<boolean expression> OR (ColA, ColB) in (select A, B ...))
   and <boolean expression>
   ...

जब प्रश्न कभी-कभी प्रकृति में तुच्छ नहीं होते हैं, तो आपके पास नियमित आंतरिक / बाहरी जॉइन करने के लिए बेस टेबल सेट तक पहुंच नहीं होती है।

यदि आप इस "हैक" का उपयोग करते हैं, तो जब आप खेतों को जोड़ते हैं तो गलत व्याख्याओं से बचने के लिए उनके बीच पर्याप्त सीमांकक जोड़ना सुनिश्चित करें, जैसे ColA + ":-:" + ColB


यह उत्तर असंगत प्रतीत होता है (निष्कर्ष का उल्लेख करता है और फिर एक अलग उदाहरण प्रदान करता है)। इसके अलावा, एक हल्के नोट पर: हमारे पास हमेशा एक विकल्प होता है ;-) मैंने
कॉन्टेक्टेशन

-3

मैंने इस तरह से आसान स्थापित किया

Select * 
from table1 
WHERE  (convert(VARCHAR,CM_PLAN_ID) + convert(VARCHAR,Individual_ID)) 
IN 
(
 Select convert(VARCHAR,CM_PLAN_ID) + convert(VARCHAR,Individual_ID)
 From CRM_VCM_CURRENT_LEAD_STATUS 
 Where Lead_Key = :_Lead_Key 
) 

उममीद है कि इससे मदद मिलेगी :)


9
आउच, यहां कोई इंडेक्स का उपयोग स्ट्रिंग कॉनसैट के लिए नहीं होता है।
mrdenny

9
मैं इसे नीचे वोट दिया है क्योंकि यह सादा खतरनाक है! यदि CM_PLAN_ID = 45और Individual_ID = 3फिर संघनन का परिणाम होता है 453- जो उस मामले से अप्रभेद्य है जहाँ CM_PLAN_ID = 4और Individual_ID = 53... परेशानी के बारे में पूछते हुए मैंने सोचा होगा
एल रोननोको

5
..of बेशक आप एक मनमाना विशेष वर्ण जैसे के साथ जोड़ सकता है 45_3या 45:3लेकिन यह अभी भी एक नहीं है अच्छा समाधान और निश्चित रूप से के रूप में @mrdenny कहते अनुक्रमित अब है कि एक को बदलने स्तंभों पर हुआ है उपयोग नहीं किया जाएगा।
एल रोनोको

1
मैंने इसे नीचे भी वोट दिया, क्योंकि यह समाधान वास्तव में केवल एक त्वरित "हैक" है। यह धीमा है और जैसा कि एल रोनोको ने कहा, इससे कीड़े हो सकते हैं।

-4

सरल और गलत तरीके से दो कॉलम को + या कॉन्टेनेट का उपयोग करके संयोजित किया जाएगा और एक कॉलम बनाया जाएगा।

Select *
from XX
where col1+col2 in (Select col1+col2 from YY)

यह बहुत धीमा होगा। प्रोग्रामिंग में उपयोग नहीं किया जा सकता है, लेकिन यदि आप किसी चीज़ के सत्यापन के लिए क्वेरी कर रहे हैं तो इसका उपयोग किया जा सकता है।


10
दरअसल, और यह त्रुटियों को जन्म दे सकता है, उदाहरण के लिए 'ab' + 'c' = 'a' + 'bc'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.