In SQL Server 2000, it was cumbersome to allow those who were not members of the sysadmin group the ability to view SQL Agent Jobs and job history through Enterprise Manager. SQL Server 2005 has made this a lot easier through the use of specialized database roles in the msdb database for viewing such information. In the scripts below, I get around these SQL 2000 restrictions with a couple of custom objects that allow you to view SQL Agent Job status and history.
First, I need to create a function that formats the job date related data from the SQL Server system tables so that it is in a format that is a bit easier on the eyes. I am creating this function in the msdb database because this is where the system tables are located. If you aren't already created backups of your msdb database, now is a really good time to start.
USE [msdb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fn_GetJobDate]
(
@LastRunDate INT,
@LastRunTime INT
)
RETURNS SMALLDATETIME
AS BEGIN
DECLARE @Date SMALLDATETIME
SET @Date =
CASE WHEN @LastRunTime > 0
THEN CAST((SUBSTRING(CAST(@LastRunDate AS VARCHAR(10)),
5, 2) + '/'
+ RIGHT(CAST(@LastRunDate AS VARCHAR(10)), 2)
+ '/'
+ LEFT(CAST(@LastRunDate AS VARCHAR(10)), 4)
+ ' '
+ CAST(CASE WHEN SUBSTRING(RIGHT(STUFF(' ', 1, 1, '000000') +
CONVERT(VARCHAR(6), @LastRunTime), 6), 1, 2) > 12
THEN SUBSTRING(RIGHT(STUFF(' ', 1, 1, '000000') +
CONVERT(VARCHAR(6), @LastRunTime), 6), 1, 2) - 12
ELSE SUBSTRING(RIGHT(STUFF(' ', 1, 1, '000000') +
CONVERT(VARCHAR(6), @LastRunTime), 6), 1, 2)
END AS VARCHAR(2)) + ':'
+ SUBSTRING(RIGHT(STUFF(' ', 1, 1, '000000')
+ convert(varchar(6), @LastRunTime),
6), 3, 2) + ':'
+ SUBSTRING(RIGHT(STUFF(' ', 1, 1, '000000')
+ convert(varchar(6), @LastRunTime),
6), 5, 2)) AS SMALLDATETIME)
ELSE NULL
END
RETURN (@Date)
END
Now that I have my function created in msdb for formatting the dates, I can create my stored procedure that pulls the job status and history. This procedure is also created in msdb, and accepts one parameter, the Job Name. You can provide the name of a specific job and it will give you job-specific details. If you omit the value for the @JobName parameter, it will return information for all jobs for the SQL Agent.
USE msdb
GO
CREATE PROCEDURE usp_GetJobInformation
(
@JobName VARCHAR(255) = NULL
)
AS
BEGIN
IF OBJECT_ID('tempdb..#Results')>0
DROP TABLE #Results
CREATE TABLE #Results
(
job_id UNIQUEIDENTIFIER NOT NULL,
last_run_date INT NOT NULL,
last_run_time INT NOT NULL,
next_run_date INT NOT NULL,
next_run_time INT NOT NULL,
next_run_schedule_id INT NOT NULL,
requested_to_run INT NOT NULL,
request_source INT NOT NULL,
request_source_id SYSNAME COLLATE DATABASE_DEFAULT NULL,
running INT NOT NULL,
current_step INT NOT NULL,
current_retry_attempt INT NOT NULL,
job_state INT NOT NULL
)
DECLARE @JobID VARCHAR(100)
SELECT TOP 1 @JobID = job_ID FROM msdb.dbo.sysjobs
INSERT INTO #Results
EXECUTE master.dbo.xp_sqlagent_enum_jobs 1, @JobID
SELECT
s.Name,
CASE WHEN s.enabled = 0 THEN 'No' ELSE 'Yes' END AS Enabled,
CASE WHEN next_run_date > 0 THEN 'Yes' ELSE 'No' END AS Scheduled,
sc.name AS Category,
current_step AS CurrentExecutionStep,
msdb.dbo.fn_GetJobDate(last_run_date,last_run_time) AS LastRunDate,
msdb.dbo.fn_GetJobDate(next_run_date, next_run_time) AS NextRunDate,
CASE WHEN xp.running = 0 THEN 'Not Running' ELSE 'Executing...' END AS Status,
ISNULL((
SELECT
CASE
WHEN run_status = 1 THEN 'Succeeded'
WHEN run_status = 3 THEN 'Cancelled'
WHEN run_status = 0 THEN 'Failed'
WHEN run_status IS NULL THEN 'Unknown'
END AS LastRunStatus
FROM
msdb..sysjobhistory sho
WHERE
sho.job_id = xp.job_id AND
sho.instance_id =
(
SELECT MAX(instance_id)
FROM msdb..sysjobhistory sj (NOLOCK)
WHERE sj.job_id = sho.job_id
)
) ,'Unknown') AS LastRunStatus
FROM #Results xp
INNER JOIN msdb..sysjobs s on xp.job_id = s.job_id
INNER JOIN msdb..syscategories sc on s.category_id = sc.category_id
WHERE
s.Name = ISNULL(@JobName, s.Name)
ORDER BY s.Name
BEGIN
IF OBJECT_ID('tempdb..#JobHistory')>0
DROP TABLE #JobHistory
CREATE TABLE #JobHistory
(
JobName SYSNAME,
StepID INT,
StepName SYSNAME,
Message NVARCHAR(1024),
RunStatus INT,
RunDate INT,
RunTime INT ,
RunDuration INT ,
operator_emailed NVARCHAR(20),
operator_netsent NVARCHAR(20),
operator_paged NVARCHAR(20)
)
INSERT INTO #JobHistory
SELECT
sjj.Name,
sjh.step_id,
sjh.step_name,
sjh.message,
sjh.run_status,
sjh.run_date,
sjh.run_time,
sjh.run_duration,
operator_emailed = so1.name,
operator_netsent = so2.name,
operator_paged = so3.name
FROM
msdb.dbo.sysjobhistory sjh
JOIN msdb.dbo.sysjobs sjj ON sjh.job_id = sjj.job_id
LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjh.operator_id_emailed = so1.id)
LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjh.operator_id_netsent = so2.id)
LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjh.operator_id_paged = so3.id),
msdb.dbo.sysjobs sj
WHERE
(sj.job_id = sjh.job_id)
SELECT
JobName, StepID, StepName,
Message,
msdb.dbo.fn_GetJobDate(RunDate, RunTime) AS LastRunTime,
CASE RunStatus
WHEN 0 THEN 'Failed'
WHEN 1 THEN 'Succeeded'
WHEN 2 THEN 'Retry (step only)'
WHEN 3 THEN 'Canceled'
WHEN 4 THEN 'In-progress message'
WHEN 5 THEN 'Unknown'
END AS RunStatus
FROM #JobHistory
ORDER BY JobName, LastRunTime DESC, StepID ASC
END
END
GO
In terms of security for the above stored procedure, you'll need to add any user or group for which you want to run the procedure as a User in the msdb database. You'll also need to give this user EXECUTE permissions on the stored procedure.
Posted
25 Feb 2009 2:05 PM
by
TimChapman