如何识别C#中是否成功执行SQL作业

我有一个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 。 如何识别作业是否成功执行。

运行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过程支持大量filter,以指定您感兴趣的作业的特定调用和/或步骤。

SQL喜欢将工作视为计划工作 – 但是没有什么可以阻止您只是临时启动工作 – 尽管它并没有真正为您提供大量支持以将您的临时工作与实例关联起来就是工作历史。 日期和它一样好(除非有人知道我不知道的伎俩。)

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

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

另外 – 在您发布的代码中 – 看起来您开始使用execJob但切换到sqlCommand – 并且有点混乱编辑。 我认为你的意思是execJob一直在进行 – 这反映在例子中。

从MSDN有关SqlCommand.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(); 

您需要运行存储的进程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}; 

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