2016-02-01 4 views
5

यहाँ के साथ मिलान पैटर्न एक समस्या मैं बार-बार Stack Exchange Data Explorer, जो T-SQL पर आधारित है के साथ खेलते हुए का सामना करना पड़ा है या नहीं:T-SQL अपवाद

को छोड़कर एक स्ट्रिंग के लिए खोज करने के लिए कैसे जब यह एक के रूप में होता कुछ अन्य स्ट्रिंग का सबस्ट्रिंग?

उदाहरण के लिए, मैं कैसे चुन सकते हैं एक मेज MyTable जहां स्तंभ MyCol स्ट्रिंग foo, लेकिन किसी भी foo कि स्ट्रिंग foobar का हिस्सा हैं अनदेखी शामिल में सभी रिकॉर्ड? कुछ

एक त्वरित और गंदे प्रयास होगा की तरह:

SELECT * 
FROM MyTable 
WHERE MyCol LIKE '%foo%' 
    AND MyCol NOT LIKE '%foobar%' 

लेकिन स्पष्ट रूप से इस मैच के लिए उदाहरण के लिए असफल हो जायेगी MyCol = 'not all foos are foobars', जो मैं मिलान करना चाहता हूं।

एक समाधान मैं ले कर आए हैं, कुछ डमी मार्कर के साथ foobar की सभी घटनाओं (कि foo की सबस्ट्रिंग नहीं है) और फिर किसी भी शेष foo रों के लिए जाँच की जगह में है:

SELECT * 
FROM MyTable 
WHERE REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%' 

यह काम करता है, लेकिन मुझे संदेह है कि यह बहुत कुशल नहीं है, क्योंकि इसे तालिका में प्रत्येक रिकॉर्ड पर REPLACE() चलाया जाना है। (SEDE के लिए, यह आमतौर पर Posts तालिका होगी, जिसमें वर्तमान में लगभग 30 मिलियन पंक्तियां हैं।) क्या ऐसा करने के कोई बेहतर तरीके हैं?

(Fwiw, the real use case कि इस सवाल का संकेत दिए जाने पर एसओ चित्र URL कि http:// योजना उपसर्ग का उपयोग लेकिन मेजबान i.stack.imgur.com को इंगित नहीं है के साथ पदों के लिए खोज रहा था।)

+0

है कि बढ़ती है IIF की वाक्यात्मक चीनी विविधता बाहर का उपयोग आप का आयोजन किया संस्करण के साथ खेल रहे हैं, या आप डेटा अपने स्थानीय सिस्टम पर साथ खेलने के लिए डाउनलोड कर रहे हैं? यदि आप स्थानीय रूप से डाउनलोड कर रहे हैं, या यदि आपको पता नहीं था कि यह विकल्प था, तो आप SQLCLR के माध्यम से RegEx कार्यक्षमता जोड़ सकते हैं। उदाहरण के लिए, आप [SQL #] (http://SQLsharp.com/) लाइब्रेरी डाउनलोड कर सकते हैं (जिसे मैंने लिखा था, लेकिन RegEx सामग्री फ्री संस्करण में है), इसे 'उपयोगिता' डीबी में स्थापित करें, और उसके बाद उपयोग करें यह इस या अन्य सामान के लिए पूछताछ में :-)। –

+0

@srutzky: मैं होस्टेड डीबी का उपयोग कर रहा हूं। मुझे लगता है कि मैं डेटा डाउनलोड करने में देख सकता हूं, लेकिन एक समाधान जो ऑनलाइन काम करता है वह बेहतर होगा। –

उत्तर

5

इनमें से कोई भी नहीं अब तक दिए गए तरीकों को विज्ञापन के रूप में काम करने की गारंटी है और केवल पंक्तियों के उप-समूह पर REPLACE निष्पादित करें।

एसक्यूएल सर्वर does not guarantee short circuiting of predicates और can move compute scalars up into the underlying query for derived tables and CTEs

केवल बात यह है कि (mostly) काम करने की गारंटी CASE बयान है। नीचे मैं CASE

SELECT * 
FROM MyTable 
WHERE 1 = IIF(MyCol LIKE '%foo%', 
       IIF(REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%', 1, 0), 
       0); 
1

एक तीन चरण फिल्टर काम करना चाहिए:

  1. '% foo%' से मेल खाने वाली सभी पंक्तियां एकत्रित करें;

  2. गैर-घटित स्ट्रिंग (जैसे 'शायद') के साथ 'foobar' के सभी उदाहरणों को प्रतिस्थापित करें;

  3. चेक फिर से '% foo%'

यहाँ मिलान के लिए आप केवल संभावित मिलान पंक्तियाँ, नहीं सभी पंक्तियों पर बदलें क्रिया। यदि आप केवल कुछ ही प्रतिशत मैच की उम्मीद कर रहे हैं, तो यह अधिक कुशल होना चाहिए।

एसक्यूएल इस प्रकार दिखाई देगा:

;with data as (
    select * 
    from MyTable 
    where MyCol like '%foo%'  
) 
select * 
from data 
where replace(MyCol, 'foobar', 'X') like '%foo%' 

ध्यान दें कि एक उप क्वेरी की आवश्यकता है, के रूप में वहाँ एसक्यूएल में कोई अभिव्यक्ति शॉर्ट-कट कर रहे हैं; इंजन एक सिंगल क्वेरी स्तर के भीतर कुशल प्रसंस्करण के लिए वांछित बूलियन शर्तों को पुन: व्यवस्थित करने के लिए स्वतंत्र है।

+0

यह सब एक ही चयन में कर रहा है जितना तेज़ –

+0

@ t-clausen.dk होगा: एसक्यूएल में बूलियन अभिव्यक्तियों की शॉर्ट-सर्किटिंग नहीं है। *** गारंटी *** का एकमात्र तरीका है कि प्रतिस्थापन और परीक्षण केवल पहले परीक्षण को पार करने वाली पंक्तियों पर किया जाता है, क्वेरी को घोंसला करना है। कोई भी किसी विशेष निष्पादन योजना द्वारा न्याय नहीं कर सकता है। –

+0

@PieterGeerkens - यह किसी भी चीज़ की गारंटी नहीं देता है। –

0

मान लिया जाये कि आप केवल रिक्त स्थान उन्हें

SELECT * 
FROM MyTable 
WHERE MyCol LIKE 'foo %' OR MyCol LIKE '% foo %' OR MyCol LIKE '% foo' 
+0

हां, यह मेल नहीं खाएगा उदा। '' एक fooing fooer foos 'foos', जिसे मैं मिलान करना चाहता हूं। मुझे प्रश्न में अपना उदाहरण अपडेट करने दें। –

+0

तो आप fooing, fooer और foos से मेल खाना चाहते हैं लेकिन foobar नहीं? –

+0

हां। वास्तविक उपयोग केस जो इस प्रश्न को प्रेरित करता था वास्तव में छवि URL के साथ पोस्ट ढूंढ रहा था जो 'http: //' योजना उपसर्ग का उपयोग करते हैं लेकिन होस्ट * i.stack.imgur.com' को * नहीं * इंगित करते हैं। –

1

यह आपके वर्तमान क्वेरी से अधिक तेजी से हो जाएगा आसपास के साथ foo के उदाहरण खोजने में रुचि रखते हैं:

SELECT * 
FROM MyTable 
WHERE 
    MyCol like '%foo%' AND 
    REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%' 

की जगह के बाद MyCol किया गया है गणना की जाती है लागू, तो यह सिर्फ तेज है:

REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%'