具有LIKE和IN条件的参数化查询

时间:2008-11-19 19:56:08

标签: .net sql parameters sql-injection parameterized

.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 个答案:

答案 0 :(得分:58)

假设您在整数数组中有类别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

的原创想法

答案 1 :(得分:11)

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.Int);
comm.Parameters["@name"].Value = "%" + Name + "%";

答案 2 :(得分:6)

这种方法不起作用。周期。

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

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

答案 3 :(得分:-2)

不确定这是否正确,但这是我在之前的方式

列出templist =新列表

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