1

I have created a function that takes a string and it returns a table with the position and character of each letter in the string. However as CTE recursion is limited to 100 levels, it fails if a string passed in is longer than that. I know I can use OPTION (MAXRECURSION [value]) to change the limit, but this does not appear to work when defining the function.

My function:

CREATE FUNCTION [dbo].[StringSplit]
(
    @String NVARCHAR(MAX)    
)
RETURNS TABLE
AS
RETURN
(   
    WITH Split(Pos,Digit)
    AS(
        SELECT 1 AS Pos, LEFT(@String, 1) AS Digit
        UNION ALL
        SELECT Pos + 1, RIGHT(LEFT(@String, Pos + 1), 1)
            FROM Split
            WHERE Pos < LEN(@String)
    )
    SELECT Pos, Digit FROM Split    
    ---OPTION (MAXRECURSION 0) -- Unable to create function if this line is UnCommented)
)

Thus the following sql code will fail due to hitting the 100 default limit:

SELECT * FROM Impact_Work.dbo.StringSplit('How long of a sentence can I possibly think of for testing thingymadoodlers out. Yes I do love the word thingymadoodlers so don''t judge me!')

Now if I add the option, it will work

SELECT * FROM Impact_Work.dbo.StringSplit('How long of a sentence can I possibly think of for testing thingymadoodlers out. Yes I do love the word thingymadoodlers so don''t judge me!')
OPTION (MAXRECURSION 0)

However, it is highly unlikely that those using this function will remember to add this extra bit to their queries so I am hoping to add this in the function it self. Is this possible? (And yes, I do ramble wildly when I need to come up with some string for testing)

2
  • 5
    How about using a different approach to splitt the string in the function? If you use a numbers table instead you don't need the recursion and it will faster. Commented May 11, 2015 at 20:15
  • The original reason for this function was to solve part of a bigger problem where I have to split values in a column so I can join the results on to another table (Think of unpivoting a column essentially). Example: a column contains the value "4213" which represents that the row first relates to the 4th attribute, then the 2nd attribute, then the first attribute etc. So I would then use this information to join to the attribute table. If this sounds confusing, or really dumb, that is because it is. But that is what the original design was for the tables so I am trying to work around it.
    – Eric S
    Commented May 12, 2015 at 18:36

3 Answers 3

2

This is what Mikael was hinting at, I believe.

You will find things work a lot quicker without that MAX parameter, are you really going to need that big a string?

CREATE FUNCTION [dbo].[StringSplit]
(
    @String NVARCHAR(MAX)    
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(   
  WITH E1(N) AS (
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
                ),                          --10E+1 or 10 rows
       E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
       E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
 cteTally(N) AS (SELECT TOP (ISNULL(DATALENGTH(@String),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4)
        SELECT N AS Pos, substring(@String, N, 1) AS Digit
        from cteTally
);
0
1

As it looks like it is not possible to change the recursion level for a specific function, I've decided to leave it as is for a few reasons. It solves the problem I designed it for and I am adding a note in the function on how people can use it for their queries should they decide to use it for other things.

0

Actually, the limit of 100 recursions is a default.

From this page: https://msdn.microsoft.com/en-us/library/ms181714.aspx

It says, in part:

MAXRECURSION number (as I see that you have found) says:

Specifies the maximum number of recursions allowed for this query. number is a nonnegative integer between 0 and 32767. When 0 is specified, no limit is applied. If this option is not specified, the default limit for the server is 100.

When the specified or default number for MAXRECURSION limit is reached during query execution, the query is ended and an error is returned.

However, recursion may be more expensive than other methods.

Note: This does not need to be a server wide setting, since it can be a query hint. If you have your own function for this string parsing, then that function can use MAXRECURSION (0) without affecting other code that may use recursion.

3
  • I could change the default, but that does affect other CTE's I've built and I do like having the safety net it provides. But for this specific one, I do know that it can easily go over 100 unlike all the others I have, so I only wanted to be able to adjust this one instead of all of them.
    – Eric S
    Commented May 11, 2015 at 20:18
  • Can you create a unique function for this task?
    – RLF
    Commented May 11, 2015 at 20:29
  • @EricS - how does one change the default value of MAXRECURSION for a system? Commented Apr 4, 2016 at 21:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.