2015/06/01

SQL Server - Utilizando Arrays de parametros en Procedimientos Almacenados

Una característica muy solicitada por los desarrolladores en SQL Server es la de poder pasar varios valores a un procedimiento almacenado en forma de array. Desde hace mucho tiempo utilizo una función de SQL que me permitía trabajar con Arrays a través de una cadena de texto delimitada por comas, normalmente los utilizaba en procesos de selección como en el ejemplo siguiente:
CREATE PROCEDURE SP_GetPerson
 @param VARCHAR(MAX)
AS
 SELECT p.BusinessEntityID,
        p.FirstName,
        p.LastName
 FROM   Person.Person p
 WHERE  p.BusinessEntityID IN (SELECT *
                               FROM   [dbo].[ArrayToTable] (@param))
 ORDER BY
        p.BusinessEntityID ASC
En este procedimiento el parametro @param recibe una cadena delimitada por comas con los valores '1,2,3,4,5', el SP_GetPerson devuelve todas las personas con estos códigos, la definición del parametro '@param' se realiza con varchar(MAX), para que la cadena pueda almacenar la mayor cantidad de códigos posible, sin embargo varchar(MAX) tiene la limitación de 8000 caracteres y en algunas situaciones se nos puede quedar pequeño.
La definición de la función en Transact-Sql es la siguiente:
CREATE FUNCTION [dbo].[ArrayToTable]
(
 @delimStr NVARCHAR(MAX)
)
RETURNS @StrValTable TABLE 
        (StrVal VARCHAR(20))
AS
BEGIN
 DECLARE @strlist     NVARCHAR(MAX),
         @pos         INT,
         @delim       CHAR,
         @lstr        NVARCHAR(MAX)
 
 SET @strlist = ISNULL(@delimStr, '')
 SET @delim = ','
 
 WHILE ((LEN(@strlist) > 0) AND (@strlist <> ''))
 BEGIN
     SET @pos = CHARINDEX(@delim, @strlist)
     
     IF @pos > 0
     BEGIN
         SET @lstr = SUBSTRING(@strlist, 1, @pos -1)
         SET @strlist = LTRIM(SUBSTRING(@strlist, CHARINDEX(@delim, @strlist) + 1, 8000))
     END
     ELSE
     BEGIN
         SET @lstr = @strlist
         SET @strlist = ''
     END
     
     INSERT @StrValTable
     VALUES
       (
         @lstr
       )
 END
 RETURN
END
GO
Básicamente lo que hace es crear una tabla temporal conformada por un campo y cada valor en un único registro, de esta forma la consulta de arriba puede ser ejecutada sin problemas, hay que tener en cuenta que el uso de tablas temporales puede reducir el rendimiento, sin embargo es mejor esto a llamar al SP muchas veces. Podriamos tambien optar por pasar los arrays con XML y readaptar la función.