Share via


SQL Server: Job Activity Monitoring by SQL Script

Issue:
Admin needs to send jobs status report to managers by email after every specific interval of time same as SQL Server builtin job activity console.
**
Solution:**
Below is the store procedure that gets status of all jobs if Job_Id is null or get specific if sends Job_Id.

USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Create Procedure [dbo].[sp_GetJobDetails] (@job_id uniqueidentifier = NULL)
As  
Begin  

--Varibale Declarations
declare @num_days int
declare @first_day datetime, @last_day datetime
declare @first_num int

if @num_days is null
set @num_days=30

set @last_day = getdate()
set @first_day = dateadd(dd, -@num_days, @last_day)

select @first_num= cast(year(@first_day) as char(4))
+replicate('0',2-len(month(@first_day)))+ cast(month(@first_day) as varchar(2))
+replicate('0',2-len(day(@first_day)))+ cast(day(@first_day) as varchar(2))

--Basic Job Information  
;With bjinfo as
(
Select 
A.job_id, B.name, Case B.enabled
When 1 Then 'Yes'
When 0 Then 'No' Else 'Unknown' End As 'Enabled',
/* -- Only for later version of SQL Server 2005 */
msdb.dbo.SQLAGENT_SUSER_SNAME(b.owner_sid) 'Job Owner',  
(Select Top 1 next_scheduled_run_date From msdb.dbo.sysjobactivity Where job_id = A.job_id Order by session_id desc) as 'NextRunDateTime',
msdb.dbo.agent_datetime(last_run_date, last_run_time) as 'LastRunDateTime',  
Case last_run_outcome
When 0 Then 'Failed'  
When 1 Then 'Succeeded'
When 2 Then 'Retry'
When 3 Then 'Cancelled'
Else 'NA' 
End Last_Run_Status, 
last_run_duration,
case
when (len(cast(last_run_duration as varchar(20))) < 3)  
then cast(last_run_duration as varchar(6))
WHEN (len(cast(last_run_duration as varchar(20))) = 3)  
then LEFT(cast(last_run_duration as varchar(6)),1) * 60  

  • RIGHT(cast(last_run_duration as varchar(6)),2)  
    WHEN (len(cast(last_run_duration as varchar(20))) = 4)  
    then LEFT(cast(last_run_duration as varchar(6)),2) * 60   
  • RIGHT(cast(last_run_duration as varchar(6)),2)  
    WHEN (len(cast(last_run_duration as varchar(20))) >= 5)  
    then (Left(cast(last_run_duration as varchar(20)),len(last_run_duration)-4)) * 3600   
    +(substring(cast(last_run_duration as varchar(20)) , len(last_run_duration)-3, 2)) * 60
  • Right(cast(last_run_duration as varchar(20)) , 2)
    End As 'Last_RunDuration',
    CONVERT(DATETIME, RTRIM(last_run_date)) + ((last_run_time + last_run_duration) * 9 + (last_run_time + last_run_duration) % 10000 * 6 
  • (last_run_time + last_run_duration) % 100 * 10) / 216e4 AS Last_RunFinishDateTime,
    Case last_run_outcome
    When 1 Then  
    Left(Replace(last_outcome_message,'The job succeeded.  The Job was invoked by',''),  
    Charindex('.',Replace(last_outcome_message,'The job succeeded.  The Job was invoked by','')))   
    When 0 Then  
    Left(Replace(last_outcome_message,'The job failed.  The Job was invoked by',''),  
    Charindex('.',Replace(last_outcome_message,'The job failed.  The Job was invoked by','')))   
    When 3 Then  
    Left(Replace(last_outcome_message,'The job was stopped prior to completion by ',''),  
    Charindex('.',Replace(last_outcome_message,'The job was stopped prior to completion by ','')))   
    End 'LastInvokedBy',  
    Case last_run_outcome
    When 3 Then  
    Left(Replace(last_outcome_message,'The job failed.  The Job was invoked by',''),  
    Charindex('.',Replace(last_outcome_message,'The job failed.  The Job was invoked by','')))   
    Else ''
    End 'Cancelled/Stopped By', 
    last_outcome_message 'Message'  
    From msdb.dbo.sysjobs B   
    Left Join (select job_id,last_run_outcome,last_outcome_message,case when last_run_date = 0
                                                          then 19900101
      else
      last_run_date end last_run_date,last_run_time,last_run_duration from msdb.dbo.SysJobServers) A on A.job_id = B.job_id
    Where ((A.job_id = @job_id  and @Job_id is not null) OR (1=1 and @Job_id is null)) 
    ),
    bjhistory as
    ( select
    jobhist.job_id,
    jobs.name,
    jobhist.step_id,
    run_dur_Casted = case 
    when (len(cast(jobhist.run_duration as varchar(20))) < 3)  
    then cast(jobhist.run_duration as varchar(6))
    WHEN (len(cast(jobhist.run_duration as varchar(20))) = 3)  
    then LEFT(cast(jobhist.run_duration as varchar(6)),1) * 60   
  • RIGHT(cast(jobhist.run_duration as varchar(6)),2)  
    WHEN (len(cast(jobhist.run_duration as varchar(20))) = 4)  
    then LEFT(cast(jobhist.run_duration as varchar(6)),2) * 60   
  • RIGHT(cast(jobhist.run_duration as varchar(6)),2) 
    WHEN (len(cast(jobhist.run_duration as varchar(20))) >= 5)  
    then (Left(cast(jobhist.run_duration as varchar(20)),len(jobhist.run_duration)-4)) * 3600   
    +(substring(cast(jobhist.run_duration as varchar(20)) , len(jobhist.run_duration)-3, 2)) * 60
  • Right(cast(jobhist.run_duration as varchar(20)) , 2)
    end
    from msdb.dbo.sysjobhistory jobhist
    Inner Join msdb.dbo.sysjobs jobs On jobhist.job_id = jobs.job_id
    where jobhist.job_id=jobs.job_id
    and jobhist.run_date>= @first_num
    and jobhist.step_id=0
    and ((jobs.job_id = @job_id  and @Job_id is not null) OR (1=1 and @Job_id is null)) 
    )
    ,bjstats
    As
    (
    Select jobs.job_id
    ,jobs.name
    ,'Sampling'=(select count(*) from bjhistory jobhist where jobhist.job_id=jobs.job_id)
    ,'run_dur_max'=(select max(run_dur_Casted) from bjhistory jobhist where jobhist.job_id=jobs.job_id)
    ,'run_dur_min'=(select min(run_dur_Casted) from bjhistory jobhist where jobhist.job_id=jobs.job_id)
    ,'run_dur_avg'=(select avg(run_dur_Casted) from bjhistory jobhist where jobhist.job_id=jobs.job_id)
    from msdb..sysjobs jobs
    Where ((jobs.job_id = @job_id  and @Job_id is not null) OR (1=1 and @Job_id is null))
    )
       select bjinfo.Name as 'Job_Name', bjinfo.Enabled,bjinfo.Last_Run_Status [Current Run Status], 
    bjinfo.LastRunDateTime [Current Run StartTime],bjinfo.Last_RunFinishDateTime [Current Run EndTime],
    Right('00'+cast(bjinfo.Last_RunDuration/3600 as varchar(10)),2)
    +':'+replicate('0',2-len((bjinfo.Last_RunDuration % 3600)/60))+cast((bjinfo.Last_RunDuration % 3600)/60 as varchar(2))
    +':'+replicate('0',2-len((bjinfo.Last_RunDuration % 3600) %60))+cast((bjinfo.Last_RunDuration % 3600)%60 as varchar(2)) 'Currnet Run Duration',
    'Avg. Duration' = cast(run_dur_avg/3600 as varchar(10))
    +':'+replicate('0',2-len((run_dur_avg % 3600)/60))+cast((run_dur_avg % 3600)/60 as varchar(2))
    +':'+replicate('0',2-len((run_dur_avg % 3600) %60))+cast((run_dur_avg % 3600)%60 as varchar(2)),
    'Max. Duration' = cast(run_dur_max/3600 as varchar(10))
    +':'+replicate('0',2-len((run_dur_max % 3600)/60))+cast((run_dur_max % 3600)/60 as varchar(2))
    +':'+replicate('0',2-len((run_dur_max % 3600) %60))+cast((run_dur_max % 3600)%60 as varchar(2)),
    'Min. Duration' = cast(run_dur_min/3600 as varchar(10))
    +':'+replicate('0',2-len((run_dur_min % 3600)/60))+cast((run_dur_min % 3600)/60 as varchar(2))
    +':'+replicate('0',2-len((run_dur_min % 3600) %60))+cast((run_dur_min % 3600)%60 as varchar(2)),
            bjstats.Sampling,bjinfo.NextRunDateTime
    From bjinfo
    left outer join bjstats on bjinfo.job_id = bjstats.job_id
    where bjinfo.name like 'DAX%' OR bjinfo.name like 'SNAPSHOT%'
    Order by bjinfo.name 
    If (@job_id is not null)
    Begin
    ;With CteJobHistory
    As
    (
    Select jobs.job_id,name,
    Case when run_status = 0 Then
    (Select Top 1 message From msdb.dbo.sysjobhistory A
    Where A.job_id = jobs.job_id and A.run_date = jobhist.run_date and A.run_time = jobhist.run_time
    and step_id = 1
    )
    Else jobhist.Message
    End Message
    ,msdb.dbo.agent_datetime(run_date,run_time) run_datetime,
    case
    when (len(cast(run_duration as varchar(20))) < 3)  
    then cast(run_duration as varchar(6))
    WHEN (len(cast(run_duration as varchar(20))) = 3)  
    then LEFT(cast(run_duration as varchar(6)),1) * 60  
  • RIGHT(cast(run_duration as varchar(6)),2)  
    WHEN (len(cast(run_duration as varchar(20))) = 4)  
    then LEFT(cast(run_duration as varchar(6)),2) * 60   
  • RIGHT(cast(run_duration as varchar(6)),2)  
    WHEN (len(cast(run_duration as varchar(20))) >= 5)  
    then (Left(cast(run_duration as varchar(20)),len(run_duration)-4)) * 3600   
    +(substring(cast(run_duration as varchar(20)) , len(run_duration)-3, 2)) * 60
  • Right(cast(run_duration as varchar(20)) , 2)
    End As 'RunDuration',
    CONVERT(DATETIME, RTRIM(run_date)) + ((run_time + run_duration) * 9 + (run_time + run_duration) % 10000 * 6 
  • (run_time + run_duration) % 100 * 10) / 216e4 AS RunFinishDateTime,
    Case run_status
    When 0 Then 'Failed'  
    When 1 Then 'Succeeded'
    When 2 Then 'Retry'
    When 3 Then 'Cancelled'
    Else 'NA' 
    End Last_Run_Status
    from msdb.dbo.sysjobhistory jobhist
    Inner Join msdb.dbo.sysjobs jobs On jobhist.job_id = jobs.job_id
    Where jobs.job_id = @job_id and step_id =0
    )Select job_id,name,message,run_datetime,
    Right('00'+cast(RunDuration/3600 as varchar(10)),2)
    +':'+replicate('0',2-len((RunDuration % 3600)/60))+cast((RunDuration % 3600)/60 as varchar(2))
    +':'+replicate('0',2-len((RunDuration % 3600) %60))+cast((RunDuration % 3600)%60 as varchar(2)) 'RunDuration', RunFinishDateTime
    Last_Run_Status From CteJobHistory
    Order by run_datetime desc
    End
    End