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

Comment passer un tableau dans une procédure stockée SQL Server

SQL Server 2008 (ou plus récent)

Tout d'abord, dans votre base de données, créez les deux objets suivants :

CREATE TYPE dbo.IDList
AS TABLE
(
  ID INT
);
GO

CREATE PROCEDURE dbo.DoSomethingWithEmployees
  @List AS dbo.IDList READONLY
AS
BEGIN
  SET NOCOUNT ON;

  SELECT ID FROM @List; 
END
GO

Maintenant dans votre code C# :

// Obtain your list of ids to send, this is just an example call to a helper utility function
int[] employeeIds = GetEmployeeIds();

DataTable tvp = new DataTable();
tvp.Columns.Add(new DataColumn("ID", typeof(int)));

// populate DataTable from your List here
foreach(var id in employeeIds)
    tvp.Rows.Add(id);

using (conn)
{
    SqlCommand cmd = new SqlCommand("dbo.DoSomethingWithEmployees", conn);
    cmd.CommandType = CommandType.StoredProcedure;
    SqlParameter tvparam = cmd.Parameters.AddWithValue("@List", tvp);
    // these next lines are important to map the C# DataTable object to the correct SQL User Defined Type
    tvparam.SqlDbType = SqlDbType.Structured;
    tvparam.TypeName = "dbo.IDList";
    // execute query, consume results, etc. here
}

SQL Server 2005

Si vous utilisez SQL Server 2005, je recommanderais toujours une fonction de fractionnement sur XML. Commencez par créer une fonction :

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
  );
GO

Maintenant, votre procédure stockée peut simplement être :

CREATE PROCEDURE dbo.DoSomethingWithEmployees
  @List VARCHAR(MAX)
AS
BEGIN
  SET NOCOUNT ON;

  SELECT EmployeeID = Item FROM dbo.SplitInts(@List, ','); 
END
GO

Et dans votre code C# il vous suffit de passer la liste sous la forme '1,2,3,12' ...

Je trouve que la méthode de transmission des paramètres de table simplifie la maintenabilité d'une solution qui l'utilise et a souvent des performances accrues par rapport à d'autres implémentations, notamment XML et le fractionnement de chaînes.

Les entrées sont clairement définies (personne n'a à deviner si le délimiteur est une virgule ou un point-virgule) et nous n'avons pas de dépendances sur d'autres fonctions de traitement qui ne sont pas évidentes sans inspecter le code de la procédure stockée.

Par rapport aux solutions impliquant un schéma XML défini par l'utilisateur au lieu d'UDT, cela implique un nombre similaire d'étapes, mais d'après mon expérience, il s'agit d'un code beaucoup plus simple à gérer, à maintenir et à lire.

Dans de nombreuses solutions, vous n'aurez peut-être besoin que d'un ou de quelques-uns de ces UDT (types définis par l'utilisateur) que vous réutilisez pour de nombreuses procédures stockées. Comme dans cet exemple, l'exigence courante est de passer par une liste de pointeurs d'ID, le nom de la fonction décrit le contexte que ces ID doivent représenter, le nom du type doit être générique.