循环并运行SQL查询数千次

时间:2018-03-16 19:41:55

标签: c# sql .net sql-server sql-server-2016

我已经阅读了几十个帖子,其中许多帖子可追溯到几年前,并且无法提供一种现代,安全且可靠的方式来将数千条记录中的特殊值更新为单个查询。

我遍历表中的所有记录,根据一些特殊逻辑确定DateTime值,然后运行这个简单的查询来更新该值...超过3500次。通过电线进行了大量的旅行。

UPDATE ScheduleTickets
    SET ScheduledStartUTC = @ScheduledStartUTC
    WHERE ScheduleId = @ScheduleId AND PatchSessionId = @PatchSessionId

通过保存和使用DataTable,我看到了不浪费内存的评论。我见过使用StringBuilder动态创建更新查询但感觉不安全/脏的解决方案。当然,整个过程不到一分钟,但必须有更好的方法。

因此,在计算出DateTime值后,我调用了......

UpdateScheduleTicketStart(ScheduleId, PatchSessionId, scheduledDateTime);

看起来像这样......

private static void UpdateScheduleTicketStart(long scheduleId, long patchSessionId, DateTime scheduledStartUTC)
{
    using (SqlConnection c = ConnectVRS())
    {
        SqlCommand cmd = new SqlCommand(@"
            UPDATE ScheduleTickets
                SET ScheduledStartUTC = @ScheduledStartUTC
                WHERE ScheduleId = @ScheduleId AND PatchSessionId = @PatchSessionId
            ", c);
        cmd.Parameters.Add("@ScheduleId", SqlDbType.BigInt).Value = scheduleId;
        cmd.Parameters.Add("@PatchSessionId", SqlDbType.BigInt).Value = patchSessionId;
        cmd.Parameters.Add("@ScheduledStartUTC", SqlDbType.VarChar).Value = scheduledStartUTC;
        cmd.ExecuteNonQuery();
    }
}

如何在一次调用中将所有值传递给SQL Server,或者如何创建单个SQL查询以便一次性执行更新?

2 个答案:

答案 0 :(得分:3)

如果值在另一个表中,请使用join

UPDATE st
    SET ScheduledStartUTC = ot.ScheduledStartUTC
    FROM ScheduleTickets st JOIN
         OtherTable ot
         ON st.ScheduleId = ot.ScheduleId AND st.PatchSessionId = ot.PatchSessionId;

您没有指定特殊逻辑,但您可以在SQL中表达它。

答案 1 :(得分:3)

很多人建议使用TableValueParameter,我同意这是一个很好的方法。以下是如何做到这一点的示例:

首先在SQL Server中创建TVP和存储过程

CREATE TYPE [dbo].[SchdeuleTicketsType] As Table
(
    ScheduledStartUTC DATETIME NOT NULL
  , ScheduleId        INT      NOT NULL
  , PatchSessionId    INT      NOT NULL
)


CREATE PROCEDURE [dbo].[usp_UpdateTickets]
(
   @ScheduleUpdates As [dbo].[SchdeuleTicketsType] Readonly
)
   AS
   Begin
        UPDATE t1
        SET t1.ScheduledStartUTC = t2.ScheduledStartUTC
        FROM ScheduleTickets AS t1
            INNER JOIN @ScheduleUpdates AS t2
        ON t1.ScheduleId = t2.ScheduleId AND
           t1.PatchSessionId  = t2.PatchSessionId 
   End
)

下一步修改代码以填充表格并将其作为参数传递给存储的proc:

    private void Populate()
    {
        DataTable dataTable = new DataTable("SchdeuleTicketUpdates");

        //we create column names as per the type in DB 
        dataTable.Columns.Add("ScheduledStartUTC", typeof(DateTime));
        dataTable.Columns.Add("ScheduleId", typeof(Int32));
        dataTable.Columns.Add("PatchSessionId", typeof(Int32));

        //write you loop to populate here

        //call the stored proc
        using (var conn = new SqlConnection(connString))
        {
            var command = new SqlCommand("[usp_UpdateTickets]");
            command.CommandType = CommandType.StoredProcedure;

            var parameter = new SqlParameter();
            //The parameter for the SP must be of SqlDbType.Structured 
            parameter.ParameterName = "@ScheduleUpdates";
            parameter.SqlDbType = System.Data.SqlDbType.Structured;
            parameter.Value = dataTable;
            command.Parameters.Add(parameter);
            command.ExecuteNonQuery();

        }
    }