我正在将几个已硬编码到应用程序中的查询转换为参数化查询。我在处理一个具有in
子句的特定查询时遇到了麻烦:
UPDATE TABLE_1 SET STATUS = 4 WHERE ID IN (1, 14, 145, 43);
第一个参数很简单,因为它只是一个普通参数:
MySqlCommand m = new MySqlCommand("UPDATE TABLE_1 SET STATUS = ? WHERE ID IN (?);");
m.Parameters.Add(new MySqlParameter("", 2));
但是,第二个参数是一个整数列表,代表需要更新的行的ID。如何为单个参数传递整数列表?或者,您将如何设置此查询,以使您不必每次调用时都完全构建它,并且可以防止SQL注入攻击?
您可以基于(可能)可变数量的参数来“动态”构建参数化查询,并对其进行迭代以将其传递。
所以,类似:
List foo; // assuming you have a List of items, in reality, it may be a List<int> or a List<myObject> with an id property, etc.
StringBuilder query = new StringBuilder( "UPDATE TABLE_1 SET STATUS = ? WHERE ID IN ( ?")
for( int i = 1; i++; i < foo.Count )
{ // Bit naive
query.Append( ", ?" );
}
query.Append( " );" );
MySqlCommand m = new MySqlCommand(query.ToString());
for( int i = 1; i++; i < foo.Count )
{
m.Parameters.Add(new MySqlParameter(...));
}
这在MySQL中是不可能的。您可以创建所需数量的参数,然后执行UPDATE ... IN(?,?,?,?)。这样可以防止注入攻击(但仍然需要您为每个参数计数重建查询)。
其他方法是传递逗号分隔的字符串并对其进行解析。
旧问题,但是如果有人通过Google遇到了这个问题,这就是我的用法:
int status = 4;
string ids = "1,14,145,43";
m.Parameters.AddWithValue("@Status", status);
m.Parameters.AddWithValue("@IDs", ids);
UPDATE TABLE_1 SET STATUS = @Status WHERE FIND_IN_SET(ID, @IDs) > 0;
注意:FIND_IN_SET是mySQL的特定功能。
信用,应归功于此:请参阅此问题:Add List<int> to a mysql parameter
您不能为IN子句使用参数。
环绕您的整数列表并执行单独的更新。
MSSQL 2008提供表值参数来避免此问题,我不知道MySQL中有任何类似的功能。
自MySQL 4.0起,您可以使用FIND_IN_SET函数来创建带有'in子句'的参数化SQL。
您的代码:
UPDATE TABLE_1 SET STATUS = 4 WHERE ID IN (1, 14, 145, 43);
已更改为使用FIND_IN_SET:
UPDATE TABLE_1 SET STATUS = 4 WHERE FIND_IN_SET(ID, 1, 14, 145, 43);
最后,您可以使用变量对查询进行参数设置:
var s = "UPDATE TABLE_1 SET STATUS = 4 WHERE FIND_IN_SET(ID, ?)";
var params = "1, 14, 145, 43";
dataSource.Execute(s, params);
请参见W3Schools reference和MySQL Tutorial
因为FIND_IN_SET是MySQL函数它不仅适用于C#,而且适用于每种语言。
我建议创建一个函数(假设mysql支持用户定义的函数)以将参数分开以返回表。