sql >> Base de Datos >  >> RDS >> Sqlserver

Pasar una estructura de lista como argumento a un procedimiento almacenado

Necesita una forma de dividir y procesar la cadena en TSQL, hay muchas formas de hacerlo. Este artículo cubre los PRO y los CONTRA de casi todos los métodos:

"Arreglos y listas en SQL Server 2005 y posteriores, cuando los parámetros de valor de tabla no Córtalo" de Erland Sommarskog

Necesitas crear una función dividida. Así es como se puede usar una función de división:

SELECT
    *
    FROM YourTable                               y
    INNER JOIN dbo.yourSplitFunction(@Parameter) s ON y.ID=s.Value

Prefiero el enfoque de tabla numérica para dividir una cadena en TSQL pero hay numerosas formas de dividir cadenas en SQL Server, vea el enlace anterior, que explica los PRO y los CONTRA de cada uno.

Para que funcione el método de tabla de números, debe realizar esta configuración de tabla de tiempo único, que creará una tabla Numbers que contiene filas del 1 al 10.000:

SELECT TOP 10000 IDENTITY(int,1,1) AS Number
    INTO Numbers
    FROM sys.objects s1
    CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)

Una vez que la tabla de Números esté configurada, cree esta función dividida:

CREATE FUNCTION [dbo].[FN_ListToTableRows]
(
     @SplitOn  char(1)      --REQUIRED, the character to split the @List string on
    ,@List     varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN 
(
    ----------------
    --SINGLE QUERY-- --this will return empty rows, and row numbers
    ----------------
    SELECT
        ROW_NUMBER() OVER(ORDER BY number) AS RowNumber
            ,LTRIM(RTRIM(SUBSTRING(ListValue, number+1, CHARINDEX(@SplitOn, ListValue, number+1)-number - 1))) AS ListValue
        FROM (
                 SELECT @SplitOn + @List + @SplitOn AS ListValue
             ) AS InnerQuery
            INNER JOIN Numbers n ON n.Number < LEN(InnerQuery.ListValue)
        WHERE SUBSTRING(ListValue, number, 1) = @SplitOn
);
GO 

Ahora puede dividir fácilmente una cadena CSV en una tabla y unirse a ella. Para realizar su tarea, si puede pasar dos parámetros, uno de claves y uno de valores, luego cree su procedimiento de esta manera:

CREATE PROCEDURE StoredProcedureName
(
     @Params1  int
    ,@Array1   varchar(8000)
    ,@Params2  int
    ,@Array2   varchar(8000)
)
AS 

DECLARE @YourTable table (col1 int, col2 int)

INSERT INTO @YourTable
        (col1, col2)
    SELECT
        a1.ListValue, a2.ListValue
        FROM dbo.FN_ListToTableRows(',',@Array1)            a1
            INNER JOIN dbo.FN_ListToTableRows(',',@Array2)  a2 ON a1.RowNumber=a2.RowNumber

select * from @YourTable

GO

pruébalo:

exec StoredProcedureName 17,'127,204,110,198',7,'162,170,163,170'

SALIDA:

(4 row(s) affected)
col1        col2
----------- -----------
127         162
204         170
110         163
198         170

(4 row(s) affected)

o si desea pasar un par de valores clave de un solo parámetro, use algo como esto:

CREATE PROCEDURE StoredProcedureName
(
     @KeyValueList  varchar(8000)
)
AS 

DECLARE @YourTable table (RowKey varchar(500), RowValue varchar(500))

INSERT INTO @YourTable
        (RowKey, RowValue)
    SELECT
        LEFT(y.ListValue,CHARINDEX(',',y.ListValue)-1),RIGHT(y.ListValue,LEN(y.ListValue)-CHARINDEX(',',y.ListValue))
        FROM dbo.FN_ListToTableRows(';',@KeyValueList) y

SELECT * FROM @YourTable

GO

ejecutarlo:

exec StoredProcedureName 'a,5;b,BBB;abc,xyz'

SALIDA:

RowKey  RowValue
------- -----------
a       5
b       BBB
abc     xyz

(3 row(s) affected)