简体   繁体   中英

Using IN operator with Stored Procedure Parameter

I am building a website in ASP.NET 2.0, some description of the page I am working about: ListView displaying a table (of posts) from my access db, and a ListBox with Multiple select mode used to filter rows (by forum name, value=forumId). I am converting the ListBox selected values into a List, then running the following query.

Parameter:

OleDbParameter("@Q",list.ToString());

Procedure:

SELECT * FROM sp_feedbacks WHERE forumId IN ([@Q])

The problem is, well, it doesn't work. Even when I run it from MSACCESS 2007 with the string 1,4, "1","4" or "1,4" I get zero results. The query works when only one forum is selected. (In (1) for instance).

  • SOLUTION? So I guess I could use WHERE with many OR's but I would really like to avoid this option. Another solution is to convert the DataTable into list then filter it using LINQ, which seems very messy option.

Thanks in advance, BBLN.

I see 2 problems here: 1) list.ToString() doesn't do what you expect. Try this:

List<int> foo = new List<int>();
foo.Add(1);
foo.Add(4);
string x = foo.ToString();

The value of "x" will be "System.Collections.Generic.List`1[System.Int32]" not "1,4" To create a comma separated list, use string.Join().

2) OleDbParameter does not understand arrays or lists. You have to do something else. Let me explain:

Suppose that you successfully use string.Join() to create the parameter. The resulting SQL will be:

SELECT * FROM sp_feedbacks WHERE forumId IN ('1,4')

The OLEDB provider knows that strings must have quotation marks around them. This is to protect you from SQL injection attacks. But you didn't want to pass a string: you wanted to pass either an array, or a literal unchanged value to go into the SQL.

You aren't the first to ask this question, but I'm afraid OLEDB doesn't have a great solution. If it were me, I would discard OLEDB entirely and use dynamic SQL. However, a Google search for "parameterized SQL array" resulted in some very good solutions here on Stack Overflow:

WHERE IN (array of IDs)

Passing an array of parameters to a stored procedure

Good Luck! Post which approach you go with!

When you have:

col in ('1,4')

This tests that col is equal to the string '1,4' . It is not testing for the values individually.

One way to solve this is using like :

where ','&@Q&',' like '*,'&col&',*'

The idea is to add delimiters to each string. So, a value of "1" becomes ",1,"in the column. A value of "1,4" for @Q becomes ",1,4,". Now when you do the comparison, there is no danger that "1" will match "10".

Note (for those who do not know). The wildcard for like is * rather than the SQL standard % . However, this might differ depending on how you are connecting, so use the appropriate wildcard.

Passing such a condition to a query has always been a problem. To a stored procedure it is worse because you can't even adjust the query to suit. 2 options currently:

  • use a table valued parameter and pass in multiple values that way (a bit of a nuisance to be honest)
  • write a "split" multi-value function as either a UDF or via SQL/CLR and call that from the query

For the record, "dapper" makes this easy for raw commands (not sprocs) via:

int[] ids = ...
var list = conn.Query<Foo>(
    "select * from Foo where Id in @ids",
    new { ids } ).ToList();

It figures out how to turn that into parameters etc for you.

Just in case anyone is looking for an SQL Server Solution:

CREATE FUNCTION [dbo].[SplitString]
(    
  @Input NVARCHAR(MAX),
  @Character CHAR(1)
)
RETURNS @Output TABLE (
  Item NVARCHAR(1000)
)
  AS BEGIN
  DECLARE @StartIndex INT, @EndIndex INT

  SET @StartIndex = 1
  IF SUBSTRING(@Input, LEN(@Input) - 1, LEN(@Input)) <> @Character
  BEGIN
        SET @Input = @Input + @Character
  END

  WHILE CHARINDEX(@Character, @Input) > 0
  BEGIN
        SET @EndIndex = CHARINDEX(@Character, @Input)

        INSERT INTO @Output(Item)
        SELECT SUBSTRING(@Input, @StartIndex, @EndIndex - 1)

        SET @Input = SUBSTRING(@Input, @EndIndex + 1, LEN(@Input))
  END

  RETURN
END

Giving an array of strings, I will convert it to a comma separated List of strings using the following code

var result = string.Join(",", arr);

Then I could pass the parameter as follows

Command.Parameters.AddWithValue("@Parameter", result);

The In Stored Procedure Definition, I would use the parameter from above as follows

select * from [dbo].[WhateverTable] where [WhateverColumn] in (dbo.splitString(@Parameter, ','))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM