C#

How to pass an array into a SQL Server stored procedure

25 September 2026 · 8 min read

How to pass an array into a SQL Server stored procedure

Passing arrays to SQL Server stored procedures can be a tricky hurdle for developers. It’s a common need – think about scenarios where you need to process multiple records at once, like bulk uploads, complex searches, or reporting across various data points. Traditional SQL parameters only allow single values, so handling arrays requires a bit of ingenuity. Fortunately, SQL Server offers several robust solutions to tackle this challenge effectively.

Table-Valued Parameters (TVPs)

TVPs are a powerful feature introduced in SQL Server 2008 that allow you to pass tabular data into stored procedures. Essentially, you define a table type within SQL Server and then use this type as a parameter in your stored procedure. This method is generally preferred for its flexibility and performance, especially when dealing with large datasets.

To use a TVP, you first create a user-defined table type. Then, declare a parameter of this type in your stored procedure. Within the procedure, you can then treat this parameter like any other table, querying and joining it as needed. This provides clean, set-based operations, promoting code readability and efficiency.

For instance, imagine updating inventory quantities for multiple products. Instead of individual updates in a loop, a TVP allows a single, set-based update, enhancing performance considerably.

Delimited Strings

Another commonly used method involves passing a delimited string to the stored procedure. This string contains the array elements separated by a specific character, such as a comma or pipe. Inside the procedure, you then parse this string to extract individual elements. While simpler to implement than TVPs, this method can be less efficient, particularly with large arrays. It also necessitates careful handling to prevent SQL injection vulnerabilities. Always sanitize and validate input when using this approach.

A practical example might be filtering a product catalog by a list of categories passed as a comma-separated string. Within the stored procedure, a function or query splits this string and uses the resulting values to filter the product table.

It is important to consider the potential drawbacks of this approach. String manipulation can be computationally expensive within the database, and improperly handled delimited strings can open doors to SQL injection attacks.

XML Parameters

Passing an XML parameter is another viable approach. You can encapsulate your array within an XML document and pass it to the stored procedure. Using SQL Server’s XML functionality, you can then parse and process the data within the procedure. This method offers more structure than delimited strings and can accommodate more complex data structures. However, it can introduce complexity in both constructing the XML on the client-side and parsing it on the server-side.

Consider a scenario where you need to insert multiple rows with related data into several tables. An XML parameter can represent this hierarchical data effectively, allowing efficient processing within the stored procedure.

Remember, XML processing can be resource-intensive, so ensure your queries are optimized for performance when working with large datasets or complex XML structures.

JSON Parameters (SQL Server 2016 and later)

With SQL Server 2016 and later versions, you can leverage JSON support to pass arrays as JSON strings. This approach provides a more flexible and structured way to handle arrays compared to delimited strings. You can use SQL Server’s JSON functions to parse the JSON array within the stored procedure. This method aligns well with modern web development practices that often utilize JSON for data exchange.

A typical use case would be processing data received from a web application in JSON format. The stored procedure can directly parse and process this JSON data, streamlining the data handling process.

Similar to XML, ensure your JSON queries are optimized for performance to avoid potential bottlenecks when dealing with large or complex datasets.

Choosing the Right Method

  • For large datasets and optimal performance, TVPs are generally recommended.
  • For smaller arrays or simple scenarios, delimited strings or JSON can be more convenient.
  • If you need to pass complex hierarchical data, XML or JSON might be more suitable.

Regardless of the method you choose, always sanitize input parameters to prevent security vulnerabilities like SQL injection. Test your stored procedures thoroughly to ensure they handle various scenarios correctly, including empty arrays, null values, and large datasets. Careful planning and proper implementation will help you leverage the full potential of array handling in SQL Server stored procedures.

  1. Assess your specific needs and data characteristics.
  2. Choose the most appropriate method based on factors like performance, data complexity, and SQL Server version.
  3. Implement the chosen approach with careful consideration for security and performance best practices.

See this article for more details on database optimization: Database Optimization Techniques.

“Stored procedures are powerful tools for data management, and understanding how to handle arrays effectively expands their capabilities significantly,” says leading database expert, [Expert Name].

Infographic Placeholder: Visual comparison of array passing methods.

FAQ

Q: What are the security considerations when passing arrays to stored procedures?

A: The primary concern is SQL injection. Always parameterize your queries, even when working with arrays, and sanitize input data to prevent malicious code execution.

Mastering these techniques allows you to harness the full potential of SQL Server stored procedures, enabling efficient and scalable data processing. Choosing the appropriate method depends on the specific requirements of your project. Consider factors like data volume, complexity, and SQL Server version to make the best decision. By implementing these strategies effectively, you can streamline your data handling processes and improve the overall performance of your applications. Explore the provided resources and continue learning to deepen your understanding of SQL Server and its powerful features. Now, you’re equipped to effectively manage and process data in your SQL Server environment.

Question & Answer :
How to pass an array into a SQL Server stored procedure?

For example, I have a list of employees. I want to use this list as a table and join it with another table. But the list of employees should be passed as parameter from C#.

SQL Server 2016 (or newer)

You can pass in a delimited list or JSON and use STRING_SPLIT() or OPENJSON().

STRING_SPLIT():

CREATE PROCEDURE dbo.DoSomethingWithEmployees @List varchar(max) AS BEGIN SET NOCOUNT ON; SELECT value FROM STRING_SPLIT(@List, ','); END GO EXEC dbo.DoSomethingWithEmployees @List = '1,2,3'; 

OPENJSON():

CREATE PROCEDURE dbo.DoSomethingWithEmployees @List varchar(max) AS BEGIN SET NOCOUNT ON; SELECT value FROM OPENJSON(CONCAT('["', REPLACE(STRING_ESCAPE(@List, 'JSON'), ',', '","'), '"]')) AS j; END GO EXEC dbo.DoSomethingWithEmployees @List = '1,2,3'; 

I wrote more about this here:

SQL Server 2008 (or newer)

First, in your database, create the following two objects:

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 

Now in your 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

If you are using SQL Server 2005, I would still recommend a split function over XML. First, create a function:

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 

Now your stored procedure can just be:

CREATE PROCEDURE dbo.DoSomethingWithEmployees @List VARCHAR(MAX) AS BEGIN SET NOCOUNT ON; SELECT EmployeeID = Item FROM dbo.SplitInts(@List, ','); END GO 

And in your C# code you just have to pass the list as '1,2,3,12'…


I find the method of passing through table valued parameters simplifies the maintainability of a solution that uses it and often has increased performance compared to other implementations including XML and string splitting.

The inputs are clearly defined (no one has to guess if the delimiter is a comma or a semi-colon) and we do not have dependencies on other processing functions that are not obvious without inspecting the code for the stored procedure.

Compared to solutions involving user defined XML schema instead of UDTs, this involves a similar number of steps but in my experience is far simpler code to manage, maintain and read.

In many solutions you may only need one or a few of these UDTs (User defined Types) that you re-use for many stored procedures. As with this example, the common requirement is to pass through a list of ID pointers, the function name describes what context those Ids should represent, the type name should be generic.