2012-09-18 9 views
5

मेरे पास एक ऐसा फ़ंक्शन है जो एक स्ट्रिंग को विभाजित करता है (स्पष्टता के अंत में चिपकाया जाता है)। यह फ़ंक्शन अकेले उपयोग किए जाने पर अपेक्षित कार्य करता है। उदाहरण:"WHERE ... IN" खंड में शामिल होने पर udf में अजीब त्रुटि

SELECT * FROM TableA WHERE TableA.id IN 
(
    SELECT value 
    FROM dbo.mg_fn_Split('2#1','#') 
) 

मैं:

SELECT value 
FROM dbo.mg_fn_Split('2#1','#') 

रिटर्न

-- value -- 
-- 2 -- 
-- 1 -- 
----------- 

लेकिन जब इस उदाहरण (TableA के बारे में अधिक बाद में) में एक "कहां में" खंड में इस्तेमाल किया, के रूप में त्रुटि: "बाएं या सबस्ट्रिंग फ़ंक्शन को पास किया गया अमान्य लंबाई पैरामीटर।"

टेबलए का उपयोग उदाहरण के रूप में किया जाता है। विभिन्न तालिकाओं का उपयोग करना (माना जाता है कि उनके पास आईडी कॉलम है) कभी-कभी सही परिणाम देता है, जबकि अन्य तालिकाओं पर मुझे त्रुटि मिलती है।

मुझे लगता है कि इसे निष्पादन के आदेश के साथ कुछ करना है, लेकिन मैं अभी भी यह देखने में असफल रहा कि फ़ंक्शन "भ्रष्ट" क्या हो सकता है।

मैं "क्या हो रहा है" स्पष्टीकरण की तलाश में हूं, न कि "इसके बजाय इसका उपयोग करें"। मुझे पता है कि परिणाम प्राप्त करने के लिए मैं उदाहरण के लिए जॉइन का उपयोग कर सकता हूं।

समारोह परिभाषा:

-- Description: Returns a table containing the results of a string-split operation. 
-- Params: 
--  DelimitedList: The string to split 
--  Delimiter: The delimiter char, defaults to ',' 
-- Columns: 
--  Position - The char index of the item 
--  Value - The actual item 
-- ============================================= 
CREATE Function [dbo].[mg_fn_Split] 
( 
    @DelimitedList nvarchar(max) 
    , @Delimiter nvarchar(2) = ',' 
) 
RETURNS TABLE 
AS 
RETURN 
    (
    With CorrectedList As 
     (
     Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End 
      + @DelimitedList 
      + Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End 
      As List 
      , Len(@Delimiter) As DelimiterLen 
     ) 
     , Numbers As 
     (
     Select TOP(Coalesce(DataLength(@DelimitedList)/2,0)) Row_Number() Over (Order By c1.object_id) As Value 
     From sys.columns As c1 
      Cross Join sys.columns As c2 
     ) 
    Select CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen As Position 
     , Substring (
        CL.List 
        , CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen  
        , CharIndex(@Delimiter, CL.list, N.Value + 1)       
         - (CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen) 
        ) As Value 
    From CorrectedList As CL 
     Cross Join Numbers As N 
    Where N.Value <= DataLength(CL.List)/2 
     And Substring(CL.List, N.Value, CL.DelimiterLen) = @Delimiter 
    ) 

संपादित करें: मैं इस प्रदर्शन करने के लिए एक बेला सेट कर लेते हैं: http://sqlfiddle.com/#!3/9f9ff/3

+3

इनलाइन यूडीएफ क्वेरी में विस्तारित हो गए हैं, इसलिए शायद कुछ शामिल संचालन या फ़िल्टर का मूल्यांकन एक अलग क्रम में किया जा रहा है जिसकी आपने अपेक्षा नहीं की थी। –

+0

जॉइन का उपयोग न करने का कारण क्या है? आईएमएचओ यदि संभव हो तो एसक्यूएल कमांड से स्ट्रिंग पार्सिंग छोड़ना सबसे अच्छा है। –

+0

मैं मार्टिन की टिप्पणी से सहमत हूं, मेरा मानना ​​है कि आपके फ़ंक्शन के लिए आपका WHERE क्लॉज टेबलए से आपके चयन * पर धक्का दिया जा रहा है। यदि आप निम्नलिखित और सबस्ट्रिंग (CL.List, N.Value, CL.DelimiterLen) = @ आपके फ़ंक्शन में डिलीमीटर को टिप्पणी करते हैं तो आपको -1 के मूल्यांकन वाले आपके सबस्ट्रिंग मानों में से एक के कारण प्रदर्शित एक ही समस्या मिल जाएगी। –

उत्तर

0

यह तब होता है जब आप आंतरिक क्वेरी में डेटा के रूप में निम्नानुसार हो जाता है।

चयन मूल्य dbo.mg_fn_Split ('#', '#') से --------------> आपको यहां त्रुटि मिलेगी।

चयन मूल्य dbo.mg_fn_Split ('2 # 1', '#') से -------------> कोई त्रुटि नहीं।

चयन मूल्य dbo.mg_fn_Split ('2', '#') से --------------------> कोई त्रुटि नहीं।

चयन मूल्य dbo.mg_fn_Split ('', '#') से ----------------------> कोई त्रुटि नहीं।

इसलिए मूल रूप से जब आप जो डेटा विभाजित कर रहे हैं और डेलीमीटर समान है तो त्रुटि होगी।

समस्या इन बयानों के साथ है।

 " Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End 
     + @DelimitedList 
     + Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End" 

अगर आप

Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '1' End 
     + @DelimitedList 
     + Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '1' End 

के लिए इसे बदल तो यह ठीक से काम करते हैं होगा .. सब आप कर रहे हैं के बजाय '' की '1' जोड़ रहा है ... उम्मीद है कि इस मदद करता है।

+0

जैसा कि मैंने पोस्ट में उल्लेख किया है, फ़ंक्शन के पैरामीटर नहीं बदलते हैं। मैंने एक पहेली जोड़ने के लिए एक संपादन किया है, समस्या के डेमो के लिए देखें। – pkExec

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