How to pass an array into a SQL Server stored procedure

前端 未结 11 2429
轻奢々
轻奢々 2020-11-21 23:28

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.

相关标签:
11条回答
  • 2020-11-21 23:40

    As others have noted above, one way to do this is to convert your array to a string and then split the string inside SQL Server.

    As of SQL Server 2016, there's a built-in way to split strings called

    STRING_SPLIT()

    It returns a set of rows that you can insert into your temp table (or real table).

    DECLARE @str varchar(200)
    SET @str = "123;456;789;246;22;33;44;55;66"
    SELECT value FROM STRING_SPLIT(@str, ';')
    

    would yield:

    value
    -----
      123
      456
      789
      246
       22
       33
       44
       55
       66
    

    If you want to get fancier:

    DECLARE @tt TABLE (
        thenumber int
    )
    DECLARE @str varchar(200)
    SET @str = "123;456;789;246;22;33;44;55;66"
    
    INSERT INTO @tt
    SELECT value FROM STRING_SPLIT(@str, ';')
    
    SELECT * FROM @tt
    ORDER BY thenumber
    

    would give you the same results as above (except the column name is "thenumber"), but sorted. You can use the table variable like any other table, so you can easily join it with other tables in the DB if you want.

    Note that your SQL Server install has to be at compatibility level 130 or higher in order for the STRING_SPLIT() function to be recognized. You can check your compatibility level with the following query:

    SELECT compatibility_level
    FROM sys.databases WHERE name = 'yourdatabasename';
    

    Most languages (including C#) have a "join" function you can use to create a string from an array.

    int[] myarray = {22, 33, 44};
    string sqlparam = string.Join(";", myarray);
    

    Then you pass sqlparam as your parameter to the stored procedure above.

    0 讨论(0)
  • 2020-11-21 23:40
    CREATE TYPE dumyTable
    AS TABLE
    (
      RateCodeId int,
      RateLowerRange int,
      RateHigherRange int,
      RateRangeValue int
    );
    GO
    CREATE PROCEDURE spInsertRateRanges
      @dt AS dumyTable READONLY
    AS
    BEGIN
      SET NOCOUNT ON;
    
      INSERT  tblRateCodeRange(RateCodeId,RateLowerRange,RateHigherRange,RateRangeValue) 
      SELECT * 
      FROM @dt 
    END
    
    0 讨论(0)
  • 2020-11-21 23:42

    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
    
    0 讨论(0)
  • 2020-11-21 23:42

    Context is always important, such as the size and complexity of the array. For small to mid-size lists, several of the answers posted here are just fine, though some clarifications should be made:

    • 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.

    With all of that said, IF the data you are using is large or is not very large yet but consistently growing, then the IEnumerable TVP method is the best choice as it streams the data to SQL Server (like the DataTable method), BUT doesn't require any duplication of the collection in memory (unlike any of the other methods). I posted an example of the SQL and C# code in this answer:

    Pass Dictionary to Stored Procedure T-SQL

    0 讨论(0)
  • 2020-11-21 23:45

    I've been searching through all the examples and answers of how to pass any array to sql server without the hassle of creating new Table type,till i found this linK, below is how I applied it to my project:

    --The following code is going to get an Array as Parameter and insert the values of that --array into another table

    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 
    

    Hope you enjoy it

    0 讨论(0)
  • 2020-11-21 23:48

    Use a table-valued parameter for your stored procedure.

    When you pass it in from C# you'll add the parameter with the data type of SqlDb.Structured.

    See here: http://msdn.microsoft.com/en-us/library/bb675163.aspx

    Example:

    // Assumes connection is an open SqlConnection object.
    using (connection)
    {
    // Create a DataTable with the modified rows.
    DataTable addedCategories =
      CategoriesDataTable.GetChanges(DataRowState.Added);
    
    // Configure the SqlCommand and SqlParameter.
    SqlCommand insertCommand = new SqlCommand(
        "usp_InsertCategories", connection);
    insertCommand.CommandType = CommandType.StoredProcedure;
    SqlParameter tvpParam = insertCommand.Parameters.AddWithValue(
        "@tvpNewCategories", addedCategories);
    tvpParam.SqlDbType = SqlDbType.Structured;
    
    // Execute the command.
    insertCommand.ExecuteNonQuery();
    }
    
    0 讨论(0)
提交回复
热议问题