仅使用一次行程更新一批记录的最简单方法是啥?
Posted
技术标签:
【中文标题】仅使用一次行程更新一批记录的最简单方法是啥?【英文标题】:What is the easiest way to update a batch of records using only one trip?仅使用一次行程更新一批记录的最简单方法是什么? 【发布时间】:2017-06-20 04:08:07 【问题描述】:通常,您将在循环内一次执行一个更新。如果您有 100 条记录,您将有 100 次访问服务器,这是不可取的。如何通过单次往返数据库更新一组记录。
using System.Data.SqlClient;
for (int ii = 0; ii < ptList.Length; ii++)
sql = @"update [CCVT].[dbo].[_tb_NCVT_Points] set PointDateTime = CONVERT(datetime, '"
+ ptList[ii]._dateDt.ToString("yyyy-MM-dd HH:mm:ss.FFF") + "', 121), PointStatus = '"
+ ptList[ii]._statStr + "', PointValue =" + ptList[ii]._valDoub.ToString()
+ " WHERE Pointkey = '" + ptList[ii]._pointName + "'; ";
theActiveConnection.Open();
SqlCommand cmd = new SqlCommand(sql, theActiveConnection);
try
cmd.ExecuteNonQuery();
cmd.Dispose();
catch (Exception eX)
//handle exceptions
请不要对这个问题投反对票。 问题How can I update multiple rows in a table with SQL query? 没有要求一趟,他们的回答也没有一趟!您是否看到 ExecuteNonQuery 操作在循环内?那不是我的问题,也不是我的答案!
foreach (DataGridViewRow row in dataGridView2.Rows)
cm.Parameters["@Qty"].Value = row.Cells[2].Value;
cm.Parameters["@Description"].Value = row.Cells[3].Value;
cm.Parameters["@Price"].Value = row.Cells[4].Value;
cm.ExecuteNonQuery();
cn.Close();
【问题讨论】:
然后只需创建一个批处理 SQL 语句并一次性运行它。或者创建存储过程并将您的数据提供给 DataTable。 How can I update multiple rows in a table with SQL query?的可能重复 您可以尝试使用世界上最快的程序,但如果您不修复称为 Sql Injection 的安全漏洞,您将遇到更大的问题 您可能需要小心处理大型多行批处理作业。关于MSSQL VS mysql 的大型工作绩效似乎有两种不同的共识。 您可以尝试Bulk Insert
或者您可以使用 xml 来执行此操作,或者您可以通过创建 UserDefined 类型并将 ListSqlCommand cmd = new SqlCommand("", theActiveConnection);
StringBuilder sql = new StringBuilder();
for (int ii = 0; ii < ptList.Length; ii++)
sql.AppendLine("UPDATE [CCVT].[dbo].[_tb_NCVT_Points]");
sql.AppendLine($"SET PointDateTime = CONVERT(datetime, @PointDateTimeii, 121), PointStatus = @PointStatusii, PointValue = @PointValueii");
sql.AppendLine($"WHERE Pointkey = '@PointKeyii;");
cmd.Parameters.AddWithValue($"@PointDateTimeii",ptList[ii]._dateDt.ToString("yyyy-MM-dd HH:mm:ss.FFF"));
cmd.Parameters.AddWithValue($"@PointStatusii",ptList[ii]._statStr);
cmd.Parameters.AddWithValue($"@PointValueii",ptList[ii]._valDoub.ToString());
cmd.Parameters.AddWithValue($"@Pointkeyii",ptList[ii]._pointName);
try
cmd.CommandText = sql.ToString();
theActiveConnection.Open();
cmd.ExecuteNonQuery();
catch (Exception eX)
//handle exceptions
finally
cmd.Dispose();
theActiveConnection.Close();
有很多方法可以处理此问题,具体取决于命令的接近程度和不同程度。在你的情况下,我认为这是最好的。
【讨论】:
你听说过一个名为 StringBuilder 的类吗? 我有,而且我确实使用了字符串生成器,我只是重新组织了@JennaLeaf 发布的代码,尽管肯定有更好的方法来构建查询字符串。 为了让你开心@Steve,我加入了一个字符串生成器。 谢谢安德鲁!你是最棒的!!!我昨晚回家了,几乎和你一样,但你的 trycatchfinallydispose() 是最好的!我喜欢你采用序列化参数的方式!谢谢!!干得好。 是的,总是在finally
中处理你的清理,这样如果你需要它在catch 中它仍然存在(无论如何都会在清理之前发生任何异常),如果有清理仍然会发生异常。【参考方案2】:
最好的执行方式是在存储过程中使用表值参数 https://msdn.microsoft.com/en-us/library/bb675163(v=vs.110).aspx
简单的方法是使用 StringBuilder 或 ... 将 SQL 语句与分号连接起来。但请注意,这有长度限制!!!
【讨论】:
前者更具可扩展性,对吗?我还查了 StringBuilder 的最大值。我不认为我会超过那个。不过你以前的方法很棒,我喜欢!我投了赞成票!!! @Jenna:请注意,不是 StringBuilder 引入了限制,而是 SQL Server...msdn.microsoft.com/de-de/library/ms143432.aspx(这里的限制也很高)【参考方案3】:为什么不使用Dapper - .Net 的简单对象映射器
var list = ptList.select(p => new
DateTime = p._dateDt,
Status = p._statStr,
Value = p._valDoub,
Key = p._pointName
);
using(var connection = new SqlConnection...)
connection.open()
connection.Execute("update [CCVT].[dbo].[_tb_NCVT_Points] set PointDateTime = @DateTime, PointStatus = @Status, PointValue = @Value
WHERE Pointkey = @Key", list);
【讨论】:
我还没试过!我使用 Linq 和 nuget,但这是我同事的项目(他是反 linq,反并发症),你放在那里的东西看起来应该可以工作!我投了赞成票。谢谢。【参考方案4】:Andrew 发布了直接答案,但这取决于您的数据来自哪里。
如果点列表已经在数据库中,并且您正在将其查询到列表中(一个带有循环的 SELECT 以填充列表),然后调用大量更新,您应该直接执行 UPDATE FROM它将 SELECT 和 UPDATE 组合在一个语句中。一次访问服务器,网络上没有不必要的行。
【讨论】:
你的也可以。就像你说的,我没有数以百万计的更新 stmts,所以 Andrew 的解决方案是我正在寻找的,特别是我不喜欢在服务器上创建一个仅合并数百条记录的 tmp 工作表。对于更大批量的更新,我肯定会使用你的。我投票赞成你的答案。另见***.com/questions/2334712/… 如果它已经在数据库中,肯定还有其他方法,但即便如此,Jenna 可能还是希望数据通过她的代码、验证、数据调整运行,但我们不这样做'不知道数据的来源,所以我发布了一个解决方案,一旦值是 OP 提供它们的位置,该解决方案将始终有效。 安德鲁,更新数据库字段的值不在数据库中,而是从某个历史引擎输入的。 @JennaLeaf 我真的不认为它们是,我只是说即使它们是,也可能有理由在将它们放回或放入另一个表之前通过 c# 运行这些值。跨度>以上是关于仅使用一次行程更新一批记录的最简单方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章