web-dev-qa-db-fra.com

Comment passer une liste en tant que paramètre dans une procédure stockée?

Vous cherchez à transmettre une liste d'ID utilisateur pour renvoyer une liste de noms. J'ai un plan pour gérer les noms générés (avec un objet COALESCE ou autre) mais j'essaie de trouver le meilleur moyen de transmettre la liste des ID utilisateur .

create procedure [dbo].[get_user_names]
@user_id_list, --which would equal a list of incoming ID numbers like (5,44,72,81,126)
@username varchar (30) output
as
select last_name+', '+first_name 
from user_mstr
where user_id in @user_id_list

Passer les valeurs pour @user_id_list est ma principale préoccupation ici.

14
shaner4011

La méthode recommandée pour transmettre un tableau de valeurs à une procédure stockée dans SQL Server consiste à utiliser des paramètres table.

D'abord, vous définissez le type comme ceci:

CREATE TYPE UserList AS TABLE ( UserID INT );

Ensuite, vous utilisez ce type dans la procédure stockée:

create procedure [dbo].[get_user_names]
@user_id_list UserList READONLY,
@username varchar (30) output
as
select last_name+', '+first_name 
from user_mstr
where user_id in (SELECT UserID FROM @user_id_list)

Donc, avant d'appeler cette procédure stockée, vous remplissez une variable de table:

DECLARE @UL UserList;
INSERT @UL VALUES (5),(44),(72),(81),(126)

Et enfin, appelez le SP:

EXEC dbo.get_user_names @UL, @username OUTPUT;
27
Matthew Sontum

Autant que je sache, il existe trois principaux candidats: les paramètres table-valeur, la chaîne de liste délimitée et la chaîne JSON.

Depuis 2016, vous pouvez utiliser le STRING_SPLIT intégré si vous voulez la route délimitée: https://docs.Microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql

Ce serait probablement l'approche la plus facile/la plus simple/la plus simple. 

De plus, depuis 2016, JSON peut être passé en tant que nvarchar et utilisé avec OPENJSON: https://docs.Microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql

C'est probablement mieux si vous avez un ensemble de données plus structuré à transmettre qui peut être considérablement variable dans son schéma. 

Les TVP, semble-t-il, étaient auparavant le moyen canonique de transmettre des paramètres plus structurés, et ils sont toujours utiles si vous avez besoin de cette structure, de son caractère explicite et du contrôle de base valeur/type. Ils peuvent être un peu plus lourds du côté des consommateurs, cependant. Si vous n'avez pas 2016+, c'est probablement l'option par défaut/la meilleure.

Je pense que c’est un compromis entre l’une de ces considérations concrètes et votre préférence pour être explicite sur la structure de vos paramètres, ce qui signifie que même si vous avez 2016+, vous préférerez peut-être indiquer explicitement le type/schéma du paramètre plutôt que passer une chaîne et l'analyser d'une manière ou d'une autre.

7
Ambrose Little

J'ai résolu ce problème de la manière suivante:

  1. En C #, j'ai construit une variable String.

string userId = "";

  1. Je mets l'élément de ma liste dans cette variable. J'ai séparé le ','.

par exemple: en C #

userId= "5,44,72,81,126";

et envoyer à SQL-Server

 SqlParameter param = cmd.Parameters.AddWithValue("@user_id_list",userId);
  1. Je crée une fonction séparée dans SQL-server pour convertir ma liste reçue (dont le type est NVARCHAR(Max)) en table.
CREATE FUNCTION dbo.SplitInts  
(  
   @List      VARCHAR(MAX),  
   @Delimiter VARCHAR(255)  
)  
RETURNS TABLE  
AS  
  RETURN ( SELECT Item = CONVERT(INT, Item) FROM  
      ( SELECT Item = x.i.value('(./text())[1]', 'varchar(max)')  
        FROM ( SELECT [XML] = CONVERT(XML, '<i>'  
        + REPLACE(@List, @Delimiter, '</i><i>') + '</i>').query('.')  
          ) AS a CROSS APPLY [XML].nodes('i') AS x(i) ) AS y  
      WHERE Item IS NOT NULL  
  );
  1. Dans la procédure de stockage principale, en utilisant la commande ci-dessous, j'utilise la liste des entrées.

SELECT user_id = Item FROM dbo.SplitInts (@user_id_list, ',');

2
BehrouzMoslem

Vous pouvez essayer ceci:

create procedure [dbo].[get_user_names]
    @user_id_list varchar(2000), -- You can use any max length

    @username varchar (30) output
    as
    select last_name+', '+first_name 
    from user_mstr
    where user_id in (Select ID from dbo.SplitString( @user_id_list, ',') )

Et voici la fonction définie par l'utilisateur pour SplitString:

Create FUNCTION [dbo].[SplitString]
(    
      @Input NVARCHAR(MAX),
      @Character CHAR(1)
)
RETURNS @Output TABLE (
      Item NVARCHAR(1000)
)
AS
BEGIN
      DECLARE @StartIndex INT, @EndIndex INT

      SET @StartIndex = 1
      IF SUBSTRING(@Input, LEN(@Input) - 1, LEN(@Input)) <> @Character
      BEGIN
            SET @Input = @Input + @Character
      END

      WHILE CHARINDEX(@Character, @Input) > 0
      BEGIN
            SET @EndIndex = CHARINDEX(@Character, @Input)

            INSERT INTO @Output(Item)
            SELECT SUBSTRING(@Input, @StartIndex, @EndIndex - 1)

            SET @Input = SUBSTRING(@Input, @EndIndex + 1, LEN(@Input))
      END

      RETURN
END
1
Sparrow

Vous pouvez utiliser cette simple méthode 'inline' pour construire un paramètre string_list_type (fonctionne dans SQL Server 2014):

declare @p1 dbo.string_list_type
insert into @p1 values(N'myFirstString')
insert into @p1 values(N'mySecondString')

Exemple d'utilisation lors de l'exécution d'un processus stocké:

exec MyStoredProc @MyParam=@p1
0
Chris Halcrow

Peut-être que vous pourriez utiliser:

select last_name+', '+first_name 
from user_mstr
where ',' + @user_id_list + ',' like '%,' + convert(nvarchar, user_id) + ',%'
0
Skippy