如何从Windows应用程序调用SQL Server代理中的作业

24

我在SQL Server Job Agent中安排了一个xyz的工作。现在我想从我的Windows应用程序中调用该工作。

6个回答

34

调用 sp_start_job 函数。

exec msdb.dbo.sp_start_job @job_name = 'YourJobName'

sp_start_job 的 MSDN 参考文献

SqlConnection DbConn = new SqlConnection(YourConnectionString);
SqlCommand ExecJob = new SqlCommand();
ExecJob.CommandType = CommandType.StoredProcedure;
ExecJob.CommandText = "msdb.dbo.sp_start_job";
ExecJob.Parameters.AddWithValue("@job_name", "YourJobName")
ExecJob.Connection = DbConn; //assign the connection to the command.

using (DbConn)
{
    DbConn.Open();
    using (ExecJob)
    {
        ExecJob.ExecuteNonQuery();
    }
}

5

使用sp_start_job方法是可行的,但它会遇到一个问题,即你不知道作业何时完成。该方法在被调用后立即返回,而非在作业完成后返回。如果这对您很重要,那么可以使用SQL Server Management Objects(SMO)编写一个函数,该函数仅在作业完成后返回。您需要添加对以下类的引用:

Microsoft.SqlServer.Management.Sdk.Sfc
Microsoft.SqlServer.Smo
Microsoft.SqlServer.SqlEnum 
Microsoft.SqlServer.ConnectionInfo

以下是代码:
Imports System.Data.SqlClient
Imports Microsoft.SqlServer.Management.Common
Imports Microsoft.SqlServer.Management.Smo
Imports Microsoft.SqlServer.Management.Smo.Agent

public void RunSQLAgentJob(string JobName)
{
    SqlConnection DbConn = new SqlConnection(connectionstring);
    ServerConnection conn;
    Job job;
    Server server;

    using (DbConn) {
        conn = new ServerConnection(DbConn);
        server = new Server(conn);
        job = server.JobServer.Jobs(JobName);
        // make sure it's not already running before starting it
        if (job.CurrentRunStatus == JobExecutionStatus.Idle) 
            job.Start();
        while (job.CurrentRunStatus == JobExecutionStatus.Executing) {
            job.Refresh();
            Console.WriteLine($"Current status of {JobName} is {job.CurrentRunStatus.ToString}");
            System.Threading.Thread.Sleep(3000);
        }
    }
}

那是什么语言?看起来几乎和C#一模一样,但C#不使用“imports”,而且Jobs()不是一个函数。 - NickG
我猜这是C#和VB.Net的混合。我是一名VB.Net程序员,代码是用那种语言写的,但由于问题是用C#标签提出的,所以我尝试将其转换为C#,但显然并没有全部正确。我应该写"using"而不是"Imports"。 - Avi
使用 System.Data.SqlClient 对我造成了错误,所以我不得不改用 Microsoft.Data.SqlClient。 - Andreas
同时,需要将“job = server.JobServer.Jobs(JobName)”改为“job = server.JobServer.Jobs[JobName]”,以确保其正常工作,因为它是一个数组而不是一个方法。 - Andreas

2

代理作业通常只是运行查询的脚本。您不能仅运行代理作业正在运行的查询吗?

代理只处理调度和故障通知等操作。这有点过于简单化,但代理大多是一个带有警报的调度程序,用于运行查询。尝试将代理作业编写为脚本,并查看是否可以将其移动到存储过程中,由代理和应用程序同时运行。


在我的情况下,我知道工作 ID。我希望通过 Windows 应用程序来更改预定的工作。 - user824910
MSDB拥有大部分代理使用的数据。在那里四处看看,虽然我自己没有这样做过,但我相信您可以直接更新它来进行更改。然而,这可能有点危险,而且在我看来,一个Windows服务似乎是您尝试做的更好的解决方案。您的OP说您想要调用它,但现在您说您想要更改它..这正确吗? - Gats
其中一个主要原因是,处理过程可能需要很长时间来计算。默认情况下,SQL CommandTimeout 只有30秒,超过这个时间后,连接将被断开。您可以延长超时时间以使连接持续更长时间,甚至使调用异步化,但仍会遇到作业可能需要30分钟左右的问题,您不希望保持连接那么长时间,特别是从 Web 服务器,您希望为用户提供手动启动作业流程的能力。这就是为什么需要这样的功能的原因。 - MikeTeeVee

2

文档中描述了所有选项。如果您不喜欢使用TSQL,可以使用C#或其他.NET语言中的SMO Job类


谢谢。你知道这是否在后台使用WMI吗? - tom redfern
@TomRedfern SMO对某些操作(例如与SQL Server服务一起工作)进行包装WMI,但对于许多操作,它只是生成TSQL并将其发送到服务器。 - Pondlife

1

0

在你的代码中 - 这部分:

while (job.CurrentRunStatus == JobExecutionStatus.Executing) {
    job.Refresh();

在我的情况下,这导致while循环条件未满足,即使SQL作业实际上已经在前一步骤中启动。 将条件更改为类似以下内容是否更好?

 while (job.CurrentRunStatus != JobExecutionStatus.Idle)

作业可能处于许多状态之一(BetweenRetriesExecutingIdlePerformingCompletionActionSuspendedWaitingForStepToFinishWaitingForWorkerThread),我怀疑这就是我的情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接