20

Eg. can I write something like this code:

public void InactiveCustomers(IEnumerable<Guid> customerIDs)
{
    //...
    myAdoCommand.CommandText =
        "UPDATE Customer SET Active = 0 WHERE CustomerID in (@CustomerIDs)";
    myAdoCommand.Parameters["@CustomerIDs"].Value = customerIDs;
    //...
}

The only way I know is to Join my IEnumerable and then use string concatenation to build my SQL string.

Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
Thomas Jespersen
  • 11,493
  • 14
  • 47
  • 55

6 Answers6

17

Generally the way that you do this is to pass in a comma-separated list of values, and within your stored procedure, parse the list out and insert it into a temp table, which you can then use for joins. As of Sql Server 2005, this is standard practice for dealing with parameters that need to hold arrays.

Here's a good article on various ways to deal with this problem:

Passing a list/array to an SQL Server stored procedure

But for Sql Server 2008, we finally get to pass table variables into procedures, by first defining the table as a custom type.

There is a good description of this (and more 2008 features) in this article:

Introduction to New T-SQL Programmability Features in SQL Server 2008

mmdemirbas
  • 9,060
  • 5
  • 45
  • 53
Eric Z Beard
  • 37,669
  • 27
  • 100
  • 145
  • 2
    http://www.sommarskog.se/arrays-in-sql-2005.html and http://www.sommarskog.se/arrays-in-sql-2000.html are the reference read on this topic. They also discuss the pros and cons in much more detail than the Vyas's one. – Remus Rusanu Aug 01 '09 at 01:26
  • There is also a newer version of E. Sommarskog's articles for SQL Server 2008 (which focuses on Table-Valued Parameters): http://www.sommarskog.se/arrays-in-sql-2008.html. I think @RemusRusanu's comment deserves its own answer; I've posted such a one: http://stackoverflow.com/a/31110710/240733 – stakx - no longer contributing Jun 29 '15 at 08:09
5

You can with SQL 2008. It hasn't been out very long, but it is available.

Jonathan Rupp
  • 15,522
  • 5
  • 45
  • 61
2

As was mentioned in a comment, Erland Sommarskog wrote a series of articles on this topic (linked-to below). The articles are very thorough and can serve as reference material. While they are specific to SQL Server (T-SQL), some of the techniques mentioned might also work for other RDBMS (such as using an XML data type):

Community
  • 1
  • 1
stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
1

You can use xml parameter type:

CREATE PROCEDURE SelectByIdList(@productIds xml) AS

DECLARE @Products TABLE (ID int) 

INSERT INTO @Products (ID) SELECT ParamValues.ID.value('.','VARCHAR(20)')
FROM @productIds.nodes('/Products/id') as ParamValues(ID) 

SELECT * FROM 
    Products
INNER JOIN 
    @Products p
ON    Products.ProductID = p.ID

http://weblogs.asp.net/jgalloway/archive/2007/02/16/passing-lists-to-sql-server-2005-with-xml-parameters.aspx

Aleris
  • 7,981
  • 3
  • 36
  • 42
-2

Nope. Parameters are like SQL values in obeying first normal form, basically, there can only be one...

As you are probably aware, generating SQL strings is risky business: you leave yourself open to an SQL injection attack. As long as you're dealing with bona fide GUID's you should be fine, but otherwise you need to be sure to cleanse your input.

Pontus Gagge
  • 17,166
  • 1
  • 38
  • 51
-2

You cannot pass a list as a single SQl Parameter. You could string.Join(',') the GUIDS such as "0000-0000-0000-0000, 1111-1111-1111-1111" but this would be high on database overhead and sub-optimal really. And you have to pass the whole string as single concatenated dynamic statement, you can't add it as a parameter.

Question:

Where are you getting your list of ID's that represent inactive customers from?

My suggestion is to approach the problem a little differently. Move all that logic into the database, something like:

    Create procedure usp_DeactivateCustomers 
    @inactive varchar(50) /*or whatever values are required to identify inactive customers*/
    AS    
    UPDATE Customer SET c.Active = 0 
    FROM Customer c JOIN tableB b ON c.CustomerID = b.CustomerID 
    WHERE b.someField = @inactive

And call it as a stored procedure:

public void InactiveCustomers(string inactive)
{
    //...
    myAdoCommand.CommandText =
        "usp_DeactivateCustomers";
    myAdoCommand.Parameters["@inactive"].Value = inactive;
    //...
}

If a list of GUID's exist in a database, why do I need to: find them; put them in a generic list; unwind the list into a CSV/XML/Table variable, just to present them back to the DB again ????? They're already there! Am I missing something?

hollystyles
  • 4,979
  • 2
  • 36
  • 38
  • Downvoted because of the very first statement in your answer, which is not generally true. I agree with the suggestions towards the end of your question, though... in some cases, it *might* indeed be possible to do everything in the DB, so the problem of how to transfer lists might never arise at all. – stakx - no longer contributing Jun 29 '15 at 07:34