带有 LIKE 和 IN 条件的参数化查询
Posted
技术标签:
【中文标题】带有 LIKE 和 IN 条件的参数化查询【英文标题】:Parameterized Queries with LIKE and IN conditions 【发布时间】:2010-09-23 02:54:28 【问题描述】:.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”(不带引号) 名称是一个字符串,可能带有单引号和其他错误字符什么是正确的语法?
【问题讨论】:
在“IN”子句中,您必须指定 SQL 命令中的每个值。并且 evenry 值添加到“参数”集合中。如果通过参数值将字符串值传递给SQL,则一定不要害怕sql注入。 你可以像WHERE name LIKE CONCAT('%', ?, '%')
这样写你的查询
Parameterize an SQL IN clause的可能重复
【参考方案1】:
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 + "%";
【讨论】:
为什么"@name", SqlDbType.Int
的数据类型是Int?
@Raza 好点。这是错误的。可能是复制/粘贴造成的错误。【参考方案2】:
不确定这是否是正确的方法,但这是我在之前做过的一种方法
list templist = 新列表
comm.Parameters.Add("@categoryids", SqlDbType.varchar); comm.Parameters["@categoryids"].value = string.join(",",templist.toarray())
【讨论】:
没有。您不能参数化值列表。好吧,你可以,但它会将 Category_ID 与单个 string 值 '1,2,3' 进行比较,而不是与列表中的每个整数值进行比较。这将产生意想不到的结果。 :-)【参考方案3】:这种方法行不通。期间。
IN 子句本身需要一个参数列表,因此当您将 one 参数绑定到它时,您就有机会传入 one 值。
使用您打算传入的各个 IN 子句占位符的确切数量动态构建您的语句字符串,然后在循环中添加参数并将值绑定到它们。
【讨论】:
另一个技巧是在SQL中创建大量参数并重复绑定值。这是不优雅的,但它有效,因为 IN (1,2,3) 和 IN (1,2,3, 1,2,3, 1,2) 是等价的谓词。 是的,不好但有效。服务器会整理出重复的。【参考方案4】:假设您在一个整数数组中有您的类别 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
【讨论】:
如果你硬编码 SQL 中的参数,即使它们是整数,你的 DBA 会发疯的,因为这意味着 DB 不能使用语句缓存,并且必须每次重新解析语句时间。 您的解决方案仍然对 sql 注入开放。例如,如果名称包含:%';删除表订单;-- @ttomsen 谢谢,不知道我是怎么错过的。现已修复以上是关于带有 LIKE 和 IN 条件的参数化查询的主要内容,如果未能解决你的问题,请参考以下文章
Sql Server参数化查询之where in和like实现详解
Sql Server参数化查询之where in和like实现详解
转载Sql Server参数化查询之where in和like实现详解
SQL Server参数化SQL语句中的like和in查询的语法(C#)