2009-12-30 7 views
12

ठीक है, पंद्रह सशर्त कॉलम प्रश्न:WHERE खंड में कॉलम पर सशर्त रूप से फ़िल्टर कैसे करें?

मैं एक संग्रहित प्रो लिख रहा हूं जो एक इनपुट पैरामीटर लेता है जो कई ध्वज स्तंभों में से एक में मैप किया गया है। अनुरोधित कॉलम पर फ़िल्टर करने का सबसे अच्छा तरीका क्या है? मैं वर्तमान में SQL2000 पर हूं, लेकिन SQL2008 पर जाने के बारे में, इसलिए यदि कोई उपलब्ध है तो मैं एक समकालीन समाधान लेगा।

तालिका sproc में पूछे लगता है कि

ID ... fooFlag barFlag bazFlag quuxFlag 
--  ------- ------- ------- -------- 
01   1  0  0   1 
02   0  1  0   0 
03   0  0  1   1 
04   1  0  0   0 

और मैं

select ID, name, description, ... 
from myTable 
where (colname like @flag + 'Flag') = 1 

की तरह कुछ करना चाहता हूँ, इसलिए यदि मैं exec uspMyProc @flag = 'foo' तरह sproc फोन मैं वापस पंक्तियों 1 और 4 प्राप्त होता

मुझे पता है कि मैं सीधे एसक्यूएल में माता-पिता में हिस्सा नहीं कर सकता। गतिशील एसक्यूएल करने के लिए, मुझे पूरी क्वेरी को स्ट्रिंग में भरना होगा, WHERE क्लॉज में @flag param को संयोजित करना होगा और फिर स्ट्रिंग को निष्पादित करना होगा। गंदे लगने के अलावा मुझे गतिशील एसक्यूएल करने के दौरान मिलता है, मेरी क्वेरी काफी बड़ी है (मैं दो दर्जन फ़ील्ड का चयन कर रहा हूं, 5 टेबल में शामिल हो रहा हूं, कुछ कार्यों को बुला रहा हूं), इसलिए यह एक पंक्ति के कारण एक बड़ी विशाल स्ट्रिंग है एक 3-लाइन WHERE फ़िल्टर में।

वैकल्पिक रूप से, मेरे पास क्वेरी की 4 प्रतियां हो सकती हैं और CASE कथन में उनके बीच चयन कर सकती हैं। यह एसक्यूएल कोड सीधे निष्पादन योग्य (और सिंटैक्स हाइलाइटिंग इत्यादि के अधीन) छोड़ देता है लेकिन कोड के बड़े हिस्से को दोहराने की लागत पर, क्योंकि मैं केवल WHERE क्लॉज पर CASE का उपयोग नहीं कर सकता।

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

आप एक मामले बयान के साथ ऐसा कर सकते हैं:

+1

"exec uspMyProc @flag = 'foo' मैं पंक्ति 1 वापस प्राप्त करूंगा।" क्यों केवल पंक्ति 1 और पंक्ति 4 भी नहीं? –

+0

@ मार्क - डी ओह, हाँ, तय! – Val

उत्तर

18

ऐसा करने के कुछ तरीके हैं।

select ID, name, description, ... 
from myTable 
where CASE 
    WHEN @flag = 'foo' then fooFlag 
    WHEN @flag = 'bar' then barFlag 
END = 1 

आप आईएफ का उपयोग कर सकते हैं।

IF (@flag = 'foo') BEGIN 
    select ID, name, description, ... 
    from myTable 
    where fooFlag = 1 
END ELSE IF (@flag = 'bar') BEGIN 
    select ID, name, description, ... 
    from myTable 
    where barFlag = 1 
END 

.... 

आप एक जटिल हो सकते हैं जहां कई कोष्ठक के साथ खंड हो सकता है।

select ID, name, description, ... 
from myTable 
where (@flag = 'foo' and fooFlag = 1) 
OR (@flag = 'bar' and barFlag = 1) OR ... 

आप गतिशील एसक्यूएल के साथ ऐसा कर सकते हैं:

DECLARE @SQL nvarchar(4000) 

SELECT @SQL = N'select ID, name, description, ... 
from myTable 
where (colname like ''' + @flag + 'Flag'') = 1' 

EXECUTE sp_ExecuteSQL @SQL, N'' 

वहाँ अधिक हैं, लेकिन मुझे लगता है कि इनमें से किसी एक तुम जा मिल जाएगा।

+0

+1 - व्यक्तिगत रूप से मैं 'केस' दृष्टिकोण का उपयोग करता हूं क्योंकि मुझे लगता है कि यह सबसे अच्छा है, हालांकि मैं एक खोजे गए मामले की बजाय एक साधारण मामले का उपयोग करता हूं जैसा कि आपने दिखाया है कि मिलान की बात स्थिर है (यानी 'केस @ फ्लैग WHEN' foo 'फिर fooFlag जब' बार 'तब बारफ्लैग END = 1') –

+0

@ ग्रेग: बेशक, यह सभी विकल्पों का सबसे खराब प्रदर्शन होने की संभावना है, क्योंकि अब आप केवल एक कॉलम को लपेट नहीं रहे हैं एक समारोह में, आप उन सभी को लपेट रहे हैं। यदि आपके पास प्रत्येक कॉलम पर एक अलग इंडेक्स है तो यह एक टेबल स्कैन बन जाता है। – Aaronaught

+0

+1 - क्वेरी की जटिलता के आधार पर। हालांकि मेरे अनुभव में जब भी क्वेरी सरल हो जाती है तब भी यह हमेशा समाप्त होती है (रखरखाव इत्यादि के दौरान) जटिल, और मैं कामना करता हूं कि मैंने गतिशील एसक्यूएल के साथ शुरुआत की थी। – Russell

4

"वैकल्पिक रूप से, मेरे पास क्वेरी की 4 प्रतियां हो सकती हैं और एक केस स्टेटमेंट में उनके बीच चयन कर सकती हैं।"

आप अपने संपूर्ण क्वेरी 4 बार नकल की जरूरत नहीं है बस क्वेरी की अपनी एक प्रति में जहां खंड में सभी संभावनाओं जोड़ें:

select ID, name, description, ... 
from myTable 
where (@flag = 'foo' and fooFlag = 1) OR (@flag = 'bar' and barFlag = 1) OR ... 
+1

+1: यह मेरा दृष्टिकोण होगा, हालांकि मैं अभी भी गतिशीलता का उपयोग करता हूं, इसलिए क्वेरी के चलते हर बार ओआरएस को ड्रैग नहीं किया जाता है। –

+0

हाँ, यह मेरा पसंदीदा समाधान है। मैंने गेब्रियल का जवाब उठाया, क्योंकि उसने मुझे कई विकल्प दिए, जैसे कि। यह वाला। – Val

0

आप प्रत्येक संभव ध्वज के लिए एक पैरामीटर हो सकता था कॉलम, फिर जांचें कि पैरामीटर शून्य है या कॉलम में मान पैरामीटर के बराबर है या नहीं। फिर आप उन झंडे के लिए 1 में प्रवेश करते हैं जिन्हें आप देखना चाहते हैं और दूसरों को शून्य छोड़ दें।

select id, name, description, ... 
from myTable 
where (@fooFlag is null or fooFlag = @fooFlag) AND 
     (@barFlag is null or barFlag = @barFlag) AND 
     ... 

ईमानदारी से, हालांकि, यह एक गतिशील LINQ क्वेरी के निर्माण और sproc लंघन एक बार आप SQL2008 करने के लिए मिल के लिए एक आदर्श उम्मीदवार की तरह लगता है।

+0

यह वही है जो मैं करूँगा यदि प्रदर्शन एक प्रमुख चिंता नहीं थी (यानी ध्वज कॉलम अनुक्रमित नहीं हैं)। – Aaronaught

+0

नहीं, मैं वास्तव में कई पैरा से बचना चाहता हूं - अधिक रखरखाव अगर मैं अधिक झंडे में विस्तार करता हूं। एक ही param के साथ, रखरखाव एसपी तक ही सीमित है; अगर मैं पैरा जोड़ता हूं, तो मुझे मौजूदा पैरामीटर में नए मानों को पास करने के बजाय, कॉलिंग कोड की संरचना भी बदलनी होगी। धन्यवाद, थो! – Val

+0

ओह, हाँ - उल्लेख करना भूल गया, क्योंकि मैं डीबी को SQL2008 में ले जा रहा हूं, मेरा ऐप एएसपी क्लासिक है, और मुझे ऐप के इस भाग को जल्द ही .NET में स्थानांतरित करने का मौका नहीं मिलेगा। तो LINQ बाहर है ... – Val

3

मैं क्या करूँगा CASE शुरुआत में कुछ चर है। उदाहरण:

DECLARE 
    @fooFlag int, 
    @barFlag int, 
    @bazFlag int, 
    @quuxFlag int 

SET @fooFlag = CASE WHEN @flag = 'foo' THEN 1 ELSE NULL END 
SET @barFlag = CASE WHEN @flag = 'bar' THEN 1 ELSE NULL END 
SET @bazFlag = CASE WHEN @flag = 'baz' THEN 1 ELSE NULL END 
SET @quuxFlag = CASE WHEN @flag = 'quux' THEN 1 ELSE NULL END 

SELECT ID, name, description, ... 
FROM myTable 
WHERE (fooFlag >= ISNULL(@fooFlag, 0) AND fooFlag <= ISNULL(@fooFlag, 1)) 
AND (barFlag >= ISNULL(@barFlag, 0) AND barFlag <= ISNULL(@barFlag, 1)) 
AND (bazFlag >= ISNULL(@bazFlag, 0) AND bazFlag <= ISNULL(@bazFlag, 1)) 
AND (quuxFlag >= ISNULL(@quuxFlag, 0) AND quuxFlag <= ISNULL(@quuxFlag, 1)) 

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

+0

यह एक उच्च प्रदर्शन सूचकांक की गारंटी नहीं देता है क्योंकि यह बारफ्लैग> = ISNULL (@barFlag, 0) का फिर से मूल्यांकन करेगा। – Russell

+0

@barFlag सिर्फ एक स्केलर वैरिएबल है, टेबल कॉलम नहीं।यह व्यवहार्य है - आप पूरी अभिव्यक्ति को 8 अलग निरंतर झंडे में विस्तारित कर सकते हैं। इसे आज़माएं और देखें। – Aaronaught

+0

क्षमाप्रार्थी, हारून, मैं आईएस नल या .. अभिव्यक्ति के साथ क्वेरी का उपयोग कर रहा था :) संख्यात्मक अभिव्यक्ति का मूल्यांकन करना ऐसा प्रतीत नहीं होता है। क्षमा करें – Russell

0
where 
    case when @value<>0 then Field else 1 end 
    = 
    case when @value<>0 then @value else 1 end 
+1

आपके कोड के आस-पास कुछ टेक्स्ट स्पष्टीकरण जोड़ने से पूछताछ में मदद मिलेगी। – RBT

0
declare @CompanyID as varchar(10) = '' -- or anyother value 

select * from EmployeeChatTbl chat 

    where chat.ConversationDetails like '%'[email protected]+'%' 

       and 
       (
        (0 = CASE WHEN (@CompanyID = '') THEN 0 ELSE 1 END) 
           or 
        (chat.CompanyID = @CompanyID) 
       ) 

काम कर जब companyID मौजूद है, फिर उस पर आधारित निस्पंदन किया जाता है, अन्य बुद्धिमान, निस्पंदन को छोड़ दिया है।

संबंधित मुद्दे