53

.Net 中的参数化查询在示例中总是如下所示:

SqlCommand comm = new SqlCommand(@"
   SELECT * 
   FROM   Products 
   WHERE  Category_ID = @categoryid
", 
   conn);
comm.Parameters.Add("@categoryid", SqlDbType.Int);
comm.Parameters["@categoryid"].Value = CategoryID;

但我在尝试执行以下操作时遇到了砖墙:

SqlCommand comm = new SqlCommand(@"
   SELECT * 
   FROM   Products 
   WHERE  Category_ID IN (@categoryids) 
      OR  name LIKE '%@name%'
", 
   conn);
comm.Parameters.Add("@categoryids", SqlDbType.Int);
comm.Parameters["@categoryids"].Value = CategoryIDs;
comm.Parameters.Add("@name", SqlDbType.Int);
comm.Parameters["@name"].Value = Name;

在哪里

  • CategoryIDs 是逗号分隔的数字列表“123,456,789”(不带引号)
  • 名称是一个字符串,可能带有单引号和其他坏字符

什么是正确的语法?

4

4 回答 4

61

假设您有一个整数数组中的类别 ID,并且 Name 是一个字符串。诀窍是创建命令文本以允许您输入所有类别 ID 作为单独的参数,并为名称构建模糊匹配。为实现前者,我们使用循环构造一系列参数名称@p0 到@pN-1,其中 N 是数组中类别 ID 的数量。然后我们构造一个参数并将其添加到命令中,并将关联的类别 id 作为每个命名参数的值。然后我们在查询本身中对名称使用连接以允许对名称进行模糊搜索。

string Name = "someone";
int[] categoryIDs = new int[] { 238, 1138, 1615, 1616, 1617,
                                1618, 1619, 1620, 1951, 1952,
                                1953, 1954, 1955, 1972, 2022 };

SqlCommand comm = conn.CreateCommand();

string[] parameters = new string[categoryIDs.Length];
for(int i=0;i<categoryIDs.Length;i++)
{
   parameters[i] = "@p"+i;
   comm.Parameters.AddWithValue(parameters[i], categoryIDs[i]);
}
comm.Parameters.AddWithValue("@name",$"%{Name}%");
comm.CommandText = "SELECT * FROM Products WHERE Category_ID IN (";
comm.CommandText += string.Join(",", parameters) + ")";
comm.CommandText += " OR name LIKE @name";

这是一个完全参数化的查询,应该会让您的 DBA 满意。我怀疑由于这些是整数,尽管直接使用值构造命令文本并仍然参数化名称不会有太大的安全风险。如果您的类别 ID 在字符串数组中,只需用逗号分割数组,将每个数组转换为整数,然后将其存储在整数数组中。

注意:我说数组并在示例中使用它,但它应该适用于任何集合,尽管您的迭代可能会有所不同。

来自http://www.tek-tips.com/viewthread.cfm?qid=1502614&page=9的原创想法

于 2008-11-19T21:26:52.063 回答
17

您需要在 sql 参数的值中使用“%”。

SqlCommand comm = new SqlCommand("SELECT * FROM Products WHERE Category_ID IN (@categoryid1, @categoryid2) OR name LIKE @name", conn);
comm.Parameters.Add("@categoryid1", SqlDbType.Int);
comm.Parameters["@categoryid1"].Value = CategoryID[0];
comm.Parameters.Add("@categoryid2", SqlDbType.Int);
comm.Parameters["@categoryid2"].Value = CategoryID[1];
comm.Parameters.Add("@name", SqlDbType.NVarChar);
comm.Parameters["@name"].Value = "%" + Name + "%";
于 2008-11-19T20:05:08.657 回答
6

这种方法行不通。时期。

IN 子句本身需要一个参数列表,因此当您将一个参数绑定到它时,您有机会传入一个值。

使用您打算传入的各个 IN 子句占位符的确切数量动态构建您的语句字符串,然后在循环中添加参数并将值绑定到它们。

于 2008-11-19T20:43:28.593 回答
-2

不确定这是否是正确的方法,但这是我在之前做过的方法

列表临时列表 = 新列表

comm.Parameters.Add("@categoryids", SqlDbType.varchar); comm.Parameters["@categoryids"].value = string.join(",",templist.toarray())

于 2008-11-19T20:37:07.140 回答