WHERE IN (array of IDs)

2019-01-07 15:53发布

I have webservice which is passed an array of ints. I'd like to do the select statement as follows but keep getting errors. Do I need to change the array to a string?

[WebMethod]
public MiniEvent[] getAdminEvents(int buildingID, DateTime startDate)
{    
    command.CommandText = @"SELECT id,
                            startDateTime, endDateTime From
                            tb_bookings WHERE buildingID IN
                            (@buildingIDs) AND startDateTime <=
                            @fromDate";

    SqlParameter buildID = new SqlParameter("@buildingIDs", buildingIDs);
}

9条回答
放我归山
2楼-- · 2019-01-07 16:37

A superfast XML Method which requires no unsafe code or user defined functions :

You can use a stored procedure and pass the comma separated list of Building IDs :

Declare @XMLList xml
SET @XMLList=cast('<i>'+replace(@buildingIDs,',','</i><i>')+'</i>' as xml)
SELECT x.i.value('.','varchar(5)') from @XMLList.nodes('i') x(i))

All credit goes to Guru Brad Schulz's Blog

查看更多
成全新的幸福
3楼-- · 2019-01-07 16:38

I use that approach and works for me.

My variable act = my list of ID's at string.

act = "1, 2, 3, 4"

 command = new SqlCommand("SELECT x FROM y WHERE x.id IN (@actions)", conn);    
 command.Parameters.AddWithValue("@actions", act);
 command.CommandText = command.CommandText.Replace("@actions", act);
查看更多
爷、活的狠高调
4楼-- · 2019-01-07 16:42

[WebMethod]

public MiniEvent[] getAdminEvents(int buildingID, DateTime startDate)

...

SqlParameter buildID= new SqlParameter("@buildingIDs", buildingIDs);

Perhaps I'm being over detailed, but this method accepts a single int, not an array of ints. If you expect to pass in an array, you will need to update your method definition to have an int array. Once you get that array, you will need to convert the array to a string if you plan to use it in a SQL query.

查看更多
干净又极端
5楼-- · 2019-01-07 16:42

Here's a Linq solution I thought up. It'll automatically insert all items in the list as parameters @item0, @item1, @item2, @item3, etc.

[WebMethod]
public MiniEvent[] getAdminEvents(Int32[] buildingIDs, DateTime startDate)
{
    // Gets a list with numbers from 0 to the max index in buildingIDs,
    // then transforms it into a list of strings using those numbers.
    String idParamString = String.Join(", ", (Enumerable.Range(0, buildingIDs.Length).Select(i => "@item" + i)).ToArray());
    command.CommandText = @"SELECT id,
                        startDateTime, endDateTime From
                        tb_bookings WHERE buildingID IN
                        (" + idParamString + @") AND startDateTime <=
                        @fromDate";
    // Reproduce the same parameters in idParamString 
    for (Int32 i = 0; i < buildingIDs.Length; i++)
            command.Parameters.Add(new SqlParameter ("@item" + i, buildingIDs[i]));
    command.Parameters.Add(new SqlParameter("@fromDate", startDate);
    // the rest of your code...
}
查看更多
乱世女痞
6楼-- · 2019-01-07 16:45

You can't (unfortunately) do that. A Sql Parameter can only be a single value, so you'd have to do:

WHERE buildingID IN (@buildingID1, @buildingID2, @buildingID3...)

Which, of course, requires you to know how many building ids there are, or to dynamically construct the query.

As a workaround*, I've done the following:

WHERE buildingID IN (@buildingID)

command.CommandText = command.CommandText.Replace(
  "@buildingID", 
  string.Join(buildingIDs.Select(b => b.ToString()), ",")
);

which will replace the text of the statement with the numbers, ending up as something like:

WHERE buildingID IN (1,2,3,4)
  • Note that this is getting close to a Sql injection vulnerability, but since it's an int array is safe. Arbitrary strings are not safe, but there's no way to embed Sql statements in an integer (or datetime, boolean, etc).
查看更多
太酷不给撩
7楼-- · 2019-01-07 16:47

NOTE: I am not generally for using unparameterized queries. IN THIS INSTANCE, however, given that we are dealing with an integer array, you could do such a thing and it would be more efficient. However, given that everyone seems to want to downgrade the answer because it doesn't meet their criteria of valid advice, I will submit another answer that performs horribly but would probably run in LINK2SQL.

Assuming, as your question states, that you have an array of ints, you can use the following code to return a string that would contain a comma delimited list that SQL would accept:

private string SQLArrayToInString(Array a)
{
 StringBuilder sb = new StringBuilder();
 for (int i = 0; i < a.GetUpperBound(0); i++)
  sb.AppendFormat("{0},", a.GetValue(i));
 string retVal = sb.ToString();
 return retVal.Substring(0, retVal.Length - 1);
}

Then, I would recommend you skip trying to parameterize the command given that this is an array of ints and just use:

command.CommandText = @"SELECT id,
            startDateTime, endDateTime From
            tb_bookings WHERE buildingID IN
            (" + SQLArrayToInString(buildingIDs) + ") AND startDateTime <=
            @fromDate";
查看更多
登录 后发表回答