Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Passer une structure de liste comme argument à une procédure stockée

Vous avez besoin d'un moyen de diviser et de traiter la chaîne dans TSQL, il existe de nombreuses façons de le faire. Cet article couvre les avantages et les inconvénients de presque toutes les méthodes :

"Tableaux et listes dans SQL Server 2005 et versions ultérieures, lorsque les paramètres de valeur de table ne le font pas Coupez-le" par Erland Sommarskog

Vous devez créer une fonction de fractionnement. Voici comment une fonction de fractionnement peut être utilisée :

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

Je préfère l'approche de la table numérique pour scinder une chaîne dans TSQL mais il existe de nombreuses façons de diviser des chaînes dans SQL Server, voir le lien précédent, qui explique les avantages et les inconvénients de chacun.

Pour que la méthode de la table des nombres fonctionne, vous devez effectuer cette configuration de table de temps unique, ce qui créera une table Numbers qui contient des lignes de 1 à 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)

Une fois la table Numbers configurée, créez cette fonction de fractionnement :

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 

Vous pouvez maintenant facilement diviser une chaîne CSV en une table et la joindre. Pour accomplir votre tâche, si vous pouvez passer deux paramètres, une clé une valeur, puis créez votre procédure comme ceci :

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

testez-le :

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

SORTIE :

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

(4 row(s) affected)

ou si vous souhaitez transmettre une seule paire de valeurs de clé de paramètre, utilisez quelque chose comme ceci :

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

lancez-le :

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

SORTIE :

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

(3 row(s) affected)