如何将数组传递到SQL Server存储过程?

例如,我有一个员工列表。我想使用这个列表作为一个表,并将它与另一个表连接。但是员工列表应该作为参数从c#传递。


当前回答

上下文总是很重要的,比如数组的大小和复杂性。对于中小型榜单来说,这里列出的几个答案还不错,但有一些需要澄清的地方:

For splitting a delimited list, a SQLCLR-based splitter is the fastest. There are numerous examples around if you want to write your own, or you can just download the free SQL# library of CLR functions (which I wrote, but the String_Split function, and many others, are completely free). Splitting XML-based arrays can be fast, but you need to use attribute-based XML, not element-based XML (which is the only type shown in the answers here, though @AaronBertrand's XML example is the best as his code is using the text() XML function. For more info (i.e. performance analysis) on using XML to split lists, check out "Using XML to pass lists as parameters in SQL Server" by Phil Factor. Using TVPs is great (assuming you are using at least SQL Server 2008, or newer) as the data is streamed to the proc and shows up pre-parsed and strongly-typed as a table variable. HOWEVER, in most cases, storing all of the data in DataTable means duplicating the data in memory as it is copied from the original collection. Hence using the DataTable method of passing in TVPs does not work well for larger sets of data (i.e. does not scale well). XML, unlike simple delimited lists of Ints or Strings, can handle more than one-dimensional arrays, just like TVPs. But also just like the DataTable TVP method, XML does not scale well as it more than doubles the datasize in memory as it needs to additionally account for the overhead of the XML document.

说了这么多,如果你使用的数据很大,或者不是很大,但一直在增长,那么IEnumerable TVP方法是最好的选择,因为它将数据流传输到SQL Server(就像DataTable方法),但不需要在内存中复制任何集合(不像任何其他方法)。我在这个回答中发布了一个SQL和c#代码的例子:

将字典传递给存储过程T-SQL

其他回答

Based on my experience, by creating a delimited expression from the employeeIDs, there is a tricky and nice solution for this problem. You should only create an string expression like ';123;434;365;' in-which 123, 434 and 365 are some employeeIDs. By calling the below procedure and passing this expression to it, you can fetch your desired records. Easily you can join the "another table" into this query. This solution is suitable in all versions of SQL server. Also, in comparison with using table variable or temp table, it is very faster and optimized solution.

CREATE PROCEDURE dbo.DoSomethingOnSomeEmployees  @List AS varchar(max)
AS
BEGIN
  SELECT EmployeeID 
  FROM EmployeesTable
  -- inner join AnotherTable on ...
  where @List like '%;'+cast(employeeID as varchar(20))+';%'
END
GO

在sql server中不支持array,但是有几种方法可以将collection传递给存储的proc。

通过使用数据表 通过使用XML。尝试将您的集合转换为xml格式,然后将其作为输入传递给存储过程

下面的链接可能会帮助你

将集合传递给存储过程

上下文总是很重要的,比如数组的大小和复杂性。对于中小型榜单来说,这里列出的几个答案还不错,但有一些需要澄清的地方:

For splitting a delimited list, a SQLCLR-based splitter is the fastest. There are numerous examples around if you want to write your own, or you can just download the free SQL# library of CLR functions (which I wrote, but the String_Split function, and many others, are completely free). Splitting XML-based arrays can be fast, but you need to use attribute-based XML, not element-based XML (which is the only type shown in the answers here, though @AaronBertrand's XML example is the best as his code is using the text() XML function. For more info (i.e. performance analysis) on using XML to split lists, check out "Using XML to pass lists as parameters in SQL Server" by Phil Factor. Using TVPs is great (assuming you are using at least SQL Server 2008, or newer) as the data is streamed to the proc and shows up pre-parsed and strongly-typed as a table variable. HOWEVER, in most cases, storing all of the data in DataTable means duplicating the data in memory as it is copied from the original collection. Hence using the DataTable method of passing in TVPs does not work well for larger sets of data (i.e. does not scale well). XML, unlike simple delimited lists of Ints or Strings, can handle more than one-dimensional arrays, just like TVPs. But also just like the DataTable TVP method, XML does not scale well as it more than doubles the datasize in memory as it needs to additionally account for the overhead of the XML document.

说了这么多,如果你使用的数据很大,或者不是很大,但一直在增长,那么IEnumerable TVP方法是最好的选择,因为它将数据流传输到SQL Server(就像DataTable方法),但不需要在内存中复制任何集合(不像任何其他方法)。我在这个回答中发布了一个SQL和c#代码的例子:

将字典传递给存储过程T-SQL

从SQL Server 2016开始,您可以将列表作为NVARCHAR()并使用OPENJSON

DECLARE @EmployeeList nvarchar(500) = '[1,2,15]'


SELECT * 
FROM Employees
WHERE ID IN (SELECT VALUE FROM OPENJSON(@EmployeeList ))

我一直在搜索所有的例子和答案,如何传递任何数组到sql server,而不需要创建新的表类型的麻烦,直到我发现了这个链接,下面是我如何将它应用到我的项目:

——下面的代码将获取一个数组作为参数,并插入该数组的值 ——数组到另一个表

Create Procedure Proc1 


@UserId int, //just an Id param
@s nvarchar(max)  //this is the array your going to pass from C# code to your Sproc

AS

    declare @xml xml

    set @xml = N'<root><r>' + replace(@s,',','</r><r>') + '</r></root>'

    Insert into UserRole (UserID,RoleID)
    select 
       @UserId [UserId], t.value('.','varchar(max)') as [RoleId]


    from @xml.nodes('//root/r') as a(t)
END 

希望大家喜欢