【问题标题】:Using IN operator with Stored Procedure Parameter将 IN 运算符与存储过程参数一起使用
【发布时间】:2013-05-17 17:34:49
【问题描述】:

我正在用 ASP.NET 2.0 构建一个网站,我正在处理的页面的一些描述: ListView 显示来自我的访问数据库的(帖子)表,以及用于过滤行的具有多选模式的 ListBox(按论坛名称,value=forumId)。 我将 ListBox 选择的值转换为 List,然后运行以下查询。

参数:

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

程序:

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

问题是,好吧,它不起作用。即使当我从 MSACCESS 2007 使用字符串 1,4、“1”、“4”或“1,4”运行它时,我得到的结果为零。仅选择一个论坛时,查询有效。 (例如在(1)中)。

  • 解决方案? 所以我想我可以将 WHERE 与许多 OR 一起使用,但我真的很想避免这个选项。 另一种解决方案是将 DataTable 转换为列表,然后使用 LINQ 对其进行过滤,这看起来很混乱。

提前致谢, BBLN。

【问题讨论】:

  • “1”和“4”不是两个单独的参数吗?
  • @Brian 我不知道,有没有办法将数组作为参数传递?
  • 不,forumId IN(@Q) 被视为forumID IN ('1,2,3,4,5')。您应该为所需的每个值创建单独的参数。

标签: c# asp.net sql ms-access


【解决方案1】:

我在这里看到 2 个问题: 1) list.ToString() 不符合您的预期。试试这个:

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

“x”的值将是“System.Collections.Generic.List`1[System.Int32]”而不是“1,4” 要创建逗号分隔列表,请使用 string.Join()。

2) OleDbParameter 不理解数组或列表。你必须做点别的。让我解释一下:

假设您成功使用 string.Join() 创建参数。生成的 SQL 将是:

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

OLEDB 提供程序知道字符串必须有引号。这是为了保护您免受 SQL 注入攻击。但是你不想传递一个字符串:你想传递一个数组,或者一个未更改的字面值以进入 SQL。

您不是第一个提出这个问题的人,但恐怕 OLEDB 没有很好的解决方案。如果是我,我会完全放弃 OLEDB 并使用动态 SQL。但是,Google 搜索“参数化 SQL 数组”在 Stack Overflow 上找到了一些非常好的解决方案:

WHERE IN (array of IDs)

Passing an array of parameters to a stored procedure

祝你好运!发布您采用哪种方法!

【讨论】:

  • 我将您的第一个建议与 Gordon 的回答结合使用。
【解决方案2】:

当你有:

col in ('1,4')

这测试 col 是否等于字符串 '1,4'。它不是单独测试这些值。

解决此问题的一种方法是使用like

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

这个想法是为每个字符串添加分隔符。因此,“1”的值在列中变为“,1”。 @Q 的值“1,4”变为“,1,4”。现在,当您进行比较时,“1”与“10”匹配是没有危险的。

注意(对于那些不知道的人)。 like 的通配符是 *,而不是 SQL 标准的 %。但是,这可能会因您的连接方式而异,因此请使用适当的通配符。

【讨论】:

  • 如果他的.Net使用OleDb连接Access db文件,Like的通配符必须是%而不是*
【解决方案3】:

将这样的条件传递给查询一直是个问题。对于存储过程,情况更糟,因为您甚至无法调整查询以适应。目前有 2 个选项:

  • 使用表值参数并以这种方式传递多个值(说实话有点麻烦)
  • 将“拆分”多值函数编写为 UDF 或通过 SQL/CLR 并从查询中调用

为了记录,“dapper”通过以下方式使原始命令(不是存储过程)变得容易:

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

它会为您计算出如何将其转化为参数等。

【讨论】:

  • 我真的很喜欢 Dapper,但它是一个学校项目,所以我需要解释整个图书馆
  • @BBLN 您可以直接在 ADO.NET 中完成 - 有点乏味,仅此而已
【解决方案4】:

以防万一有人在寻找 SQL Server 解决方案:

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

给出一个字符串数组,我将使用以下代码将其转换为逗号分隔的字符串列表

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

那我可以按如下方式传递参数

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

在存储过程定义中,我将使用上面的参数如下

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

【讨论】:

    猜你喜欢
    • 2013-04-29
    • 1970-01-01
    • 2012-12-01
    • 2013-09-10
    • 2015-06-18
    • 2011-07-29
    • 2012-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多