问题
I have a function that splits up a string (pasted at the end for clarity). This function works as expected when used alone. Example:
SELECT value
FROM dbo.mg_fn_Split('2#1','#')
Returns
-- value --
-- 2 --
-- 1 --
-----------
But when used in a "WHERE IN" clause, as in this example (more on tableA later on):
SELECT * FROM TableA WHERE TableA.id IN
(
SELECT value
FROM dbo.mg_fn_Split('2#1','#')
)
I get the error: "Invalid length parameter passed to the LEFT or SUBSTRING function."
TableA is used here as an example. Using different tables (assuming they have the id column) sometimes returns correct results, while on other tables I get the error.
I'm assuming it has something to do with order of execution, but I still fail to see what could "corrupt" the function.
I'm looking for a "what's happening" explanation, not a "use this instead". I know I can use joins for example to get the results.
The function definition:
-- 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
)
EDIT: I've set up a fiddle to exhibit this: http://sqlfiddle.com/#!3/9f9ff/3
回答1:
This happens when you data in inner query becomes as follows.
SELECT value FROM dbo.mg_fn_Split('#','#') --------------> You will get error here.
SELECT value FROM dbo.mg_fn_Split('2#1','#') -------------> No error here.
SELECT value FROM dbo.mg_fn_Split('2','#') --------------------> No error here.
SELECT value FROM dbo.mg_fn_Split('','#') ----------------------> No error here.
so basically when the data you are splitting and the delimiter is same the error will happen.
The problem is with these statements.
" Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
+ @DelimitedList
+ Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End"
if you change this to
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
then it will work out fine.. all you are doing is adding '1' instead of ''... hope this helps.
来源:https://stackoverflow.com/questions/12480321/weird-error-in-udf-when-included-in-where-in-clause