如何在C#中监视SQL Server代理作业信息

时间:2010-09-21 04:35:36

标签: c# sql-server-2000 sql-server-agent

当作业发生时,我需要创建一个用于监视SQL Server 2000代理作业状态和信息的应用程序,与Windows应用程序事件日志中显示的相同。现在我已经通过连接字符串连接到数据库,但我不知道如何从Job获取状态和信息。

我需要在Textbox上显示状态和信息。

你有什么建议怎么办?

开发者工具:

  1. MS SQL Sever 2000 SP4
  2. MS Visual Studio 2008(C#)
  3. 我是菜鸟程序员。

6 个答案:

答案 0 :(得分:5)

我已经可以这样做了......

我在数据库“msdb”中选择表格“Sysjobserver”,以获取我想要的工作的阅读状态,日期和时间。

使用此代码

public void GetJobsAndStatus()
        {
            string sqlJobQuery = "select j.job_id, j.name, j.enabled, jh.run_status," +
            " js.last_outcome_message, jh.run_date, jh.step_name, jh.run_time" +
            " from sysjobs j left join sysjobhistory jh on (j.job_id = jh.job_id)" +
            " left join sysjobservers js on (j.job_id = js.job_id)" +
            " where jh.run_date = (select Max(run_date) from sysjobhistory)" +
            " and jh.run_time = (select Max(run_time) from sysjobhistory)";

            // create SQL connection and set up SQL Command for query
            using (SqlConnection _con = new SqlConnection("server=10.15.13.70;database=msdb;user id=sa;pwd="))
            using (SqlCommand _cmd = new SqlCommand(sqlJobQuery, _con))

            {

                try
               {
               // open connection
               _con.Open();
               SqlConnection.ClearPool(_con);

               // create SQL Data Reader and grab data
               using (SqlDataReader rdr = _cmd.ExecuteReader())
               {
                   // as long as we get information from the reader
                   while (rdr.Read())
                   {
                       Guid jobID = rdr.GetGuid(0);             // read Job_id
                       string jobName = rdr.GetString(1);       // read Job name
                       byte jobEnabled = rdr.GetByte(2);        // read Job enabled flag
                       int jobStatus = rdr.GetInt32(3);         // read last_run_outcome from sysjobserver
                       string jobMessage = rdr.GetString(4);    // read Message from sysjobserver
                       int jobRunDate = rdr.GetInt32(5);        // read run_date from sysjobhistory
                       string jobStepName = rdr.GetString(6);   // read StepName from sysjobhistory
                       int jobRunTime = rdr.GetInt32(7);        // read run_time from sysjobhistory


                        String[] lviData = new String[] // ตัวแปรอะเรย์ชื่อ lviData 
                    { 
                        jobID.ToString(),
                        jobName.ToString(),
                        jobStepName.ToString(),
                        jobMessage.ToString(), 
                        jobStatus.ToString(),
                        jobRunDate.ToString(),
                        jobRunTime.ToString(),
                        //jobEnabled.ToString(), 

                    };

                        newData = lviData;

                        DisplayList();  // for display data on datagridview


                   }

                   rdr.Close();
               }
           }

非常感谢大家的帮助。 :-D

答案 1 :(得分:3)

查询的SQL存储过程不会为您提供任何系统数据,除非您在msdb系统数据库上拥有db_owner权限,至少在SQL Server 2008中。因此,所提到的方法通常不适用于您要显示的应用程序或管理工作。但是,SMO命名空间为您提供了许多SQL Server管理功能的托管代码解决方案,包括SQL Server代理函数,这些函数只需要您通常可以为应用程序用户排序的SQLServerAgent *权限。这里给出了使用SMO类来处理作业的一个很好的介绍:

http://www.codeproject.com/Tips/367470/Manage-SQL-Server-Agent-Jobs-using-Csharp

我现在正在处理类似的任务,而SQL查询让我拒绝访问,使用C#代码和Microsoft.SqlServer.Management.Smo.Agent命名空间我刚刚使用此代码列出了所有作业:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo.Agent;

namespace SmoTest
{
    class Program
    {
        static readonly string SqlServer = @"SQL01\SQL01";

        static void Main(string[] args)
        {
            ServerConnection conn = new ServerConnection(SqlServer);
            Server server = new Server(conn);
            JobCollection jobs = server.JobServer.Jobs;
            foreach (Job job in jobs)
            {
                Console.WriteLine(job.Name);
            }
        }
    }
}

答案 2 :(得分:2)

这应该是一个很好的起点,了解如何使用T-SQL查找SQL代理作业:

View (and disable) SQL Agent Jobs with TSQL

该脚本将列出您数据库中的所有作业,以及下次运行它们的时间等等。

使用job_name,您还应该能够使用服务器上msdb数据库中的SQL Server Agent Stored Procedures找到有关您的工作的详细信息。

答案 3 :(得分:1)

SQL Server 2005及更高版本上,您可以使用系统存储过程msdb.dbo.sp_help_job获取有关SQL Server代理作业的信息,包括状态。您可以在http://msdn.microsoft.com/en-us/library/ms186722(v=SQL.90).aspx了解有关sp_help_job的更多信息。

以下是使用C#执行此操作的示例代码。

private Dictionary<int, string> ExecutionStatusDictionary = new Dictionary<int, string>()
{
    {0, "Not idle or suspended"},
    {1, "Executing"},
    {2, "Waiting for thread"},
    {3, "Between retries"},
    {4, "Idle"},
    {5, "Suspended"},
    {7, "Performing completion actions"}
};

public string GetStatus()
{
    SqlConnection msdbConnection = new SqlConnection("Data Source=SERVERNAME;Initial Catalog=msdb;Integrated Security=SSPI");
    System.Text.StringBuilder resultBuilder = new System.Text.StringBuilder();

    try
    {
        msdbConnection.Open();

        SqlCommand jobStatusCommand = msdbConnection.CreateCommand();

        jobStatusCommand.CommandType = CommandType.StoredProcedure;
        jobStatusCommand.CommandText = "sp_help_job";

        SqlParameter jobName = jobStatusCommand.Parameters.Add("@job_name", SqlDbType.VarChar);
        jobName.Direction = ParameterDirection.Input;
        jobName.Value = "LoadRegions";

        SqlParameter jobAspect = jobStatusCommand.Parameters.Add("@job_aspect", SqlDbType.VarChar);
        jobAspect.Direction = ParameterDirection.Input;
        jobAspect.Value = "JOB";

        SqlDataReader jobStatusReader = jobStatusCommand.ExecuteReader();

        while (jobStatusReader.Read())
        {
            resultBuilder.Append(string.Format("{0} {1}",
                jobStatusReader["name"].ToString(),
                ExecutionStatusDictionary[(int)jobStatusReader["current_execution_status"]]
            ));
        }
        jobStatusReader.Close();
    }
    finally
    {
        msdbConnection.Close();
    }

    return resultBuilder.ToString();
}

答案 4 :(得分:0)

您可以使用此SELECT获取所有服务器作业的列表:

SELECT [name] FROM msdb.dbo.sysjobs

如果您想获得当前正在运行的作业及其信息的列表,我建议您在应用程序调用的SQL中编写存储过程。这里有一个很好的演示,你可以使用......

http://feodorgeorgiev.com/blog/2010/03/how-to-query-currently-running-sql-server-agent-jobs/

祝你好运!

答案 5 :(得分:0)

对于我的用例,我特别需要知道作业何时完成运行以及它是否成功。这是我的代码:

using System;
using System.Data;
using System.Data.SqlClient;

namespace LaunchJobAndWaitTillDone
{
    class Program
    {
        const string connectionString = "Data Source=YOURSERVERNAMEHERE;Initial Catalog=msdb;Integrated Security=SSPI";
        const string jobName = "YOURJOBNAMEHERE";
        static readonly TimeSpan waitFor = TimeSpan.FromSeconds(1.0);

        enum JobExecutionResult
        {
            Succeeded,
            FailedToStart,
            FailedAfterStart,
            Unknown
        }

        static void Main(string[] args)
        {
            var instance = new Program();
            JobExecutionResult jobResult = instance.RunJob(jobName);

            switch (jobResult)
            {
                case JobExecutionResult.Succeeded:
                    Console.WriteLine($"SQL Server Agent job, '{jobName}', ran successfully to completion.");
                    break;
                case JobExecutionResult.FailedToStart:
                    Console.WriteLine($"SQL Server Agent job, '{jobName}', failed to start.");
                    break;
                case JobExecutionResult.FailedAfterStart:
                    Console.WriteLine($"SQL Server Agent job, '{jobName}', started successfully, but encountered an error.");
                    break;
                default:
                    Console.WriteLine($"Unknown result from attempting to run SQL Server Agent job, '{jobName}'.");
                    break;
            }

            Console.ReadLine();
            return;
        }

        JobExecutionResult RunJob(string jobName)
        {
            int jobResult;

            using (var jobConnection = new SqlConnection(connectionString))
            {
                SqlCommand jobCommand;
                SqlParameter jobReturnValue;
                SqlParameter jobParameter;

                jobCommand = new SqlCommand("sp_start_job", jobConnection);
                jobCommand.CommandType = CommandType.StoredProcedure;

                jobReturnValue = new SqlParameter("@RETURN_VALUE", SqlDbType.Int);
                jobReturnValue.Direction = ParameterDirection.ReturnValue;
                jobCommand.Parameters.Add(jobReturnValue);

                jobParameter = new SqlParameter("@job_name", SqlDbType.VarChar);
                jobParameter.Direction = ParameterDirection.Input;
                jobCommand.Parameters.Add(jobParameter);
                jobParameter.Value = jobName;

                jobConnection.Open();
                try
                {
                    jobCommand.ExecuteNonQuery();
                    jobResult = (Int32)jobCommand.Parameters["@RETURN_VALUE"].Value;
                }
                catch (SqlException)
                {
                    jobResult = -1;
                }
            }

            switch (jobResult)
            {
                case 0:
                    break;
                default:
                    return JobExecutionResult.FailedToStart;
            }

            while (true)
            {
                using (var jobConnection2 = new SqlConnection(connectionString))
                {
                    SqlCommand jobCommand2 = new SqlCommand("sp_help_jobactivity", jobConnection2);
                    jobCommand2.CommandType = CommandType.StoredProcedure;

                    SqlParameter jobReturnValue2 = new SqlParameter("@RETURN_VALUE", SqlDbType.Int);
                    jobReturnValue2.Direction = ParameterDirection.ReturnValue;
                    jobCommand2.Parameters.Add(jobReturnValue2);

                    SqlParameter jobParameter2 = new SqlParameter("@job_name", SqlDbType.VarChar);
                    jobParameter2.Direction = ParameterDirection.Input;
                    jobCommand2.Parameters.Add(jobParameter2);
                    jobParameter2.Value = jobName;

                    jobConnection2.Open();
                    SqlDataReader rdr = jobCommand2.ExecuteReader();
                    while (rdr.Read())
                    {
                        object msg = rdr["message"];
                        object run_status = rdr["run_status"];
                        if (!DBNull.Value.Equals(msg))
                        {
                            var message = msg as string;
                            var runStatus = run_status as Int32?;
                            if (message != null && message.StartsWith("The job succeeded")
                                && runStatus.HasValue && runStatus.Value == 1)
                            {
                                return JobExecutionResult.Succeeded;
                            }
                            else if (message != null && message.StartsWith("The job failed"))
                            {
                                return JobExecutionResult.FailedAfterStart;
                            }
                            else if (runStatus.HasValue && runStatus.Value == 1)
                            {
                                return JobExecutionResult.Unknown;
                            }
                        }
                    }
                }

                System.Threading.Thread.Sleep(waitFor);
            }
        }
    }
}

请注意,您可能需要数据库/服务器所有者权限或类似的权限,此代码才能正常工作。