【问题标题】:How to Identify whether SQL job is successfully executed or not in C#如何在 C# 中识别 SQL 作业是否成功执行
【发布时间】:2015-09-29 00:13:37
【问题描述】:

我有一个 C# 方法来执行 SQL 作业。它成功地执行了 SQL 作业。 并且代码运行良好。

我为此使用标准 SQL 存储过程 msdb.dbo.sp_start_job

这是我的代码..

public int ExcecuteNonquery()
{
     var result = 0;
     using (var execJob =new SqlCommand())
     {
          execJob.CommandType = CommandType.StoredProcedure;
          execJob.CommandText = "msdb.dbo.sp_start_job";
          execJob.Parameters.AddWithValue("@job_name", "myjobname");
          using (_sqlConnection)
          {
               if (_sqlConnection.State == ConnectionState.Closed) 
                  _sqlConnection.Open();

               sqlCommand.Connection = _sqlConnection;
               result = sqlCommand.ExecuteNonQuery();

               if (_sqlConnection.State == ConnectionState.Open) 
                 _sqlConnection.Close();
          }
     }
     return result;
}

这是在作业中执行的 sp

ALTER PROCEDURE [Area1].[Transformation]
              AS 
              BEGIN
              SET NOCOUNT ON;

              SELECT NEXT VALUE FOR SQ_COMMON
              -- Transform Master Data
              exec [dbo].[sp_Transform_Address];
              exec [dbo].[sp_Transform_Location];
              exec [dbo].[sp_Transform_Product];
              exec [dbo].[sp_Transform_Supplier];
              exec [dbo].[sp_Transform_SupplierLocation];

              -- Generate Hierarchies and Product References
              exec [dbo].[sp_Generate_HierarchyObject] 'Area1',FGDemand,1;
              exec [dbo].[sp_Generate_HierarchyObject] 'Area1',RMDemand,2;
              exec [dbo].[sp_Generate_Hierarchy] 'Area1',FGDemand,1;
              exec [dbo].[sp_Generate_Hierarchy] 'Area1',RMDemand,2;
              exec [dbo].[sp_Generate_ProductReference] 'Area1',FGDemand,1;
              exec [dbo].[sp_Generate_ProductReference] 'Area1',RMDemand,2;

              -- Transform Demand Allocation BOM 
              exec [Area1].[sp_Transform_FGDemand];
              exec [Area1].[sp_Transform_FGAllocation];
              exec [Area1].[sp_Transform_RMDemand];
              exec [Area1].[sp_Transform_RMAllocation];
              exec [Area1].[sp_Transform_BOM];
              exec [Area1].[sp_Transform_RMDemand_FK];

              -- Transform Purchasing Document Data
              exec [dbo].[sp_Transform_PurchasingDoc];
              exec [dbo].[sp_Transform_PurchasingItem];
              exec [dbo].[sp_Transform_ScheduleLine];


              exec [dbo].[sp_CalculateRequirement] 'Area1'
              exec [dbo].[sp_Create_TransformationSummary] 'Area1'
              -- Trauncate Integration Tables 
              exec [dbo].[sp_TruncateIntegrationTables] 'Area1'

              END

问题是,即使作业执行成功与否,它总是返回-1。如何确定作业是否成功执行。

【问题讨论】:

  • 你能告诉我们你的StoredProcedure吗?
  • 这是一个标准的sql
  • 如果你有 SET NOCOUNT ON;一开始,您的返回结果将始终为 -1,因为您在过程中关闭了有关受影响行的信息,所以这很重要。
  • 要监控作业状态,您可以使用存储过程MSDB.dbo.sp_help_job。参见例如How to Execute and Monitor an Agent Job Using T-SQL in SQL Server 2005/2008。只需将其包装在 .NET 代码中即可。
  • 我同意 MicSim,因为这些作业是异步的,SQL 在某处注册这些作业,我认为它在 sysjobhistory 中?因此,当 SQL 将作业状态更新为成功或失败时,您必须等待。

标签: c# sql stored-procedures ado.net


【解决方案1】:

来自MSDNSqlCommand.ExecuteNonQuery 方法:

对于 UPDATE、INSERT 和 DELETE 语句,返回值是受命令影响的行数。当正在插入或更新的表上存在触发器时,返回值包括受插入或更新操作影响的行数以及受一个或多个触发器影响的行数。对于所有其他类型的语句,返回值为 -1。如果发生回滚,返回值也是-1。

在这一行:

result = sqlCommand.ExecuteNonQuery();

您想返回受命令影响的行数并将其保存到一个 int 变量,但由于语句的类型是 select,所以它返回 -1。如果您使用INSERTDELETEUPDATE 语句对其进行测试,您将得到正确的结果。

顺便说一句,如果您想获取受SELECT 命令影响的行数并将其保存到 int 变量中,您可以尝试如下操作:

select count(*) from jobs where myjobname = @myjobname

然后使用ExecuteScalar得到正确的结果:

result = (int)execJob.ExecuteScalar();

【讨论】:

    【解决方案2】:

    运行msdb.dbo.sp_start_job 后,返回码被映射到一个输出参数。您有机会控制参数的名称​​在执行之前

    public int StartMyJob( string connectionString )
    {
     using (var sqlConnection = new SqlConnection( connectionString ) )
     {
       sqlConnection.Open( );
       using (var execJob = sqlConnection.CreateCommand( ) )
       {
          execJob.CommandType = CommandType.StoredProcedure;
          execJob.CommandText = "msdb.dbo.sp_start_job";
          execJob.Parameters.AddWithValue("@job_name", "myjobname");
          execJob.Parameters.Add( "@results", SqlDbType.Int ).Direction = ParameterDirection.ReturnValue;      
          execJob.ExecuteNonQuery();
          return ( int ) sqlCommand.Parameters["results"].Value;
        }
      }
    }
    

    您需要知道返回码的数据类型才能执行此操作 - 对于 sp_start_job,它是 SqlDbType.Int

    但是,这只是开始工作的结果,值得了解,而不是运行你的工作的结果。要获得作业的运行结果,您可以定期执行:

    msdb.dbo.sp_help_job @jobName
    

    该过程返回的一列是last_run_outcome,可能包含您真正感兴趣的内容。它仍在运行时将是 5(未知)。

    一个作业通常是多个步骤 - 每个步骤可能会或可能不会根据先前步骤的结果执行。另一个称为sp_help_jobhistory 的过程支持大量过滤器来指定您感兴趣的工作的特定调用和/或步骤。

    SQL 喜欢将作业视为计划的工作 - 但没有什么可以阻止您刚刚开始临时作业 - 尽管它并没有真正为您提供很多支持来将临时作业与实例相关联工作经历。日期几乎是最好的(除非有人知道我不知道的技巧。)

    我已经在运行它之前看到了该作业的位置创建临时作业,因此当前的临时执行是唯一返回的执行。但是你最终会得到很多重复或几乎重复的工作,这些工作永远不会再次执行。如果你走那条路,你必须计划事后清理。

    关于您使用 _sqlConnection 变量的说明。你不想那样做。您的代码处理了它,但它显然是在调用此方法之前在其他地方创建的。那是糟糕的juju。您最好只创建连接并以相同的方法处理它。依靠 SQL 连接池来加快连接速度——这可能已经打开了。

    另外 - 在您发布的代码中 - 看起来您从 execJob 开始但切换到 sqlCommand - 并且有点搞砸了编辑。我以为您一直指的是 execJob - 这反映在示例中。

    【讨论】:

      【解决方案3】:

      您需要运行存储过程 msdb.dbo.sp_help_job

           private int CheckAgentJob(string connectionString, string jobName) {
              SqlConnection dbConnection = new SqlConnection(connectionString);
              SqlCommand command = new SqlCommand();
              command.CommandType = System.Data.CommandType.StoredProcedure;
              command.CommandText = "msdb.dbo.sp_help_job";
              command.Parameters.AddWithValue("@job_name", jobName);
              command.Connection = dbConnection;
              using (dbConnection)
              {
                  dbConnection.Open();      
                  using (command){
                      SqlDataReader reader = command.ExecuteReader();
                      reader.Read();
                      int status = reader.GetInt32(21); // Row 19 = Date Row 20 = Time 21 = Last_run_outcome
                      reader.Close();
                      return status;
                  }
              }
           }
      
      enum JobState { Failed = 0, Succeeded = 1, Retry = 2, Cancelled = 3, Unknown = 5};
      

      继续对未知进行轮询,直到得到答案。让我们希望它成功:-)

      【讨论】:

        猜你喜欢
        • 2018-09-06
        • 1970-01-01
        • 1970-01-01
        • 2017-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-19
        • 2021-03-08
        相关资源
        最近更新 更多