【发布时间】:2015-08-11 18:02:11
【问题描述】:
我正在尝试使用参数化命令执行多个插入查询,但我收到了语法异常。 sql 中的查询如下所示:
CREATE TEMPORARY TABLE IF NOT EXISTS TEMP_PTO (
ng_id INT,
requested_hours DECIMAL(7,4)
);
INSERT INTO TEMP_PTO VALUES
(1, 0.0000), (2, 1.5000);
我通过以下方式在 C# 中生成它,其中ptoHours 是包含ng_id 和requested_hours 的类的IEnumerable。 Queries 是一个包含查询文本的resx 文件,而Queries.PTOLoadTempCommand = INSERT INTO TEMP_PTO VALUES @v;:
using (var conn = new MySqlConnection(this.connString))
{
MySqlTransaction trans = null;
try
{
await conn.OpenAsync();
trans = conn.BeginTransaction();
using (var tempCommand = conn.CreateCommand())
{
tempCommand.CommandText = Queries.PTOTempTableCommand;
await tempCommand.ExecuteNonQueryAsync();
}
using (var loadCommand = conn.CreateCommand())
{
loadCommand.CommandText = Queries.PTOLoadTempCommand; //INSERT INTO TEMP_PTO VALUES @v;
loadCommand.Parameters.AddWithValue("@v", String.Join(", " ,ptoHours.Select(p => String.Format("({0}, {1:N4})", p.AgentId, p.UsedVacationHours))));
//Exception thrown here
var affected = await loadCommand.ExecuteNonQueryAsync();
if (affected != entryCount)
throw new Exception("Not All Entries Loaded");
}
trans.Commit();
}
catch (Exception e)
{
if(trans!= null) trans.Rollback();
}
}
查看loadCommand对象,可以看到参数@v的值为(1, 0.0000), (2, 1.5000)。你能做这样的插入还是我需要修改函数一次插入一个?我知道我可以走@987654334@ 路线,但是我不能使用参数化的安全性。
【问题讨论】:
-
您可以同时使用 StringBuilder 和参数化查询,您只需要确保“构建”尽可能多的参数即可。也就是说,根据我的经验,在循环中执行准备好的参数化查询所需的时间与执行多值插入所需的时间差别不大。 (对于大量数据,可以将两者进行最佳组合,例如准备一次插入 10 行的参数化语句,但它高度依赖于情境。)
-
您是否需要一次只插入 2 个值?如果是这种情况,@Sami 是对的,您可以在事务中进行 2 次插入,这很好。如果以后你需要插入数千行,你最好去 MySqlBulkLoader 之类的其他东西
-
@sroll 我只以 2 为例。它将平均加载 1,300 - 2k 个条目。您可以批量加载到临时表中吗?
-
@JRLambert 您可以肯定地使用 SqlServer 和 Oracle,但抱歉我不知道使用 MySql。有 1000-2000 个条目,我认为开始考虑批量插入可能会更好