Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

So übergeben Sie ein Array an eine gespeicherte SQL Server-Prozedur

SQL Server 2008 (oder neuer)

Erstellen Sie zunächst in Ihrer Datenbank die folgenden zwei Objekte:

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

Jetzt in Ihrem C#-Code:

// 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

Wenn Sie SQL Server 2005 verwenden, würde ich immer noch eine Split-Funktion über XML empfehlen. Erstellen Sie zuerst eine Funktion:

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

Jetzt kann Ihre gespeicherte Prozedur nur sein:

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

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

Und in Ihrem C#-Code müssen Sie die Liste nur als '1,2,3,12' übergeben ...

Ich finde, dass die Methode zum Übergeben von Tabellenwertparametern die Wartbarkeit einer Lösung vereinfacht, die sie verwendet, und im Vergleich zu anderen Implementierungen, einschließlich XML und String-Splitting, häufig eine höhere Leistung aufweist.

Die Eingaben sind klar definiert (niemand muss erraten, ob das Trennzeichen ein Komma oder ein Semikolon ist) und wir haben keine Abhängigkeiten von anderen Verarbeitungsfunktionen, die nicht offensichtlich sind, ohne den Code für die gespeicherte Prozedur zu untersuchen.

Im Vergleich zu Lösungen mit benutzerdefiniertem XML-Schema anstelle von UDTs umfasst dies eine ähnliche Anzahl von Schritten, aber meiner Erfahrung nach ist der Code viel einfacher zu verwalten, zu warten und zu lesen.

In vielen Lösungen benötigen Sie möglicherweise nur einen oder wenige dieser UDTs (benutzerdefinierte Typen), die Sie für viele gespeicherte Prozeduren wiederverwenden. Wie bei diesem Beispiel besteht die allgemeine Anforderung darin, eine Liste von ID-Zeigern zu übergeben, der Funktionsname beschreibt, welchen Kontext diese IDs darstellen sollen, der Typname sollte generisch sein.