-- The simple fixed-length function, which is waterproof when using fn_nums -
-- at least it will never miss an element. Query plan on the other hand...
CREATE FUNCTION fn_fixstring_single(@str nvarchar(MAX), @itemlen tinyint)
RETURNS TABLE
RETURN(SELECT listpos = n.Number,
              str = rtrim(convert(nvarchar(4000),
                      substring(@str, @itemlen * (n.Number - 1) + 1, @itemlen)))
       FROM   fn_nums(len(@str) / @itemlen +
                      CASE len(@str) % @itemlen WHEN 0 THEN 0 ELSE 1 END) AS n)
go

-- A special version for integers that works on a binary string. CREATE FUNCTION fn_fixbinary_single(@str varbinary(MAX)) RETURNS TABLE AS RETURN(SELECT listpos = n.Number, n = convert(int, substring(@str, 4 * (n.Number - 1) + 1, 4)) FROM fn_nums(datalength(@str) / 4 ) AS n) go
-- The same as fixstring_single, but as a multi-statement function. CREATE FUNCTION fn_fixstring_mstmt(@str nvarchar(MAX), @itemlen tinyint) RETURNS @t TABLE (listpos int NOT NULL, str nvarchar(4000) NOT NULL) AS BEGIN INSERT @t (listpos, str) SELECT listpos = n.Number, str = rtrim( substring(@str, @itemlen * (n.Number - 1) + 1, @itemlen)) FROM fn_nums(len(@str) / @itemlen + CASE len(@str) % @itemlen WHEN 0 THEN 0 ELSE 1 END) n RETURN END