the actual problem is well described and answered on the question below:
How and when does SQL Agent update next_run_date/next_run_time values?
one solution I found is to use the procedure below shows the next running time of a job, even if you have just created it.
just pass the jobName as parameter.
use master
go
CREATE PROCEDURE [dbo].[sp_ViewJobListing]
(
@JobName VARCHAR(255)=NULL
)
AS
/*
http://www.techrepublic.com/blog/the-enterprise-cloud/how-do-i-assign-permissions-to-users-to-see-sql-agent-jobs/
sp_ViewJobListing @jobname = 'ADS Full MetaData Refresh'
*/
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,
last_run_date,
next_run_date,
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
IF @JobName IS NOT NULL
BEGIN
CREATE TABLE #JobHistory
(
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
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
sjj.Name = @JobName and
(sj.job_id = sjh.job_id)
SELECT
StepID, StepName, Message, RunDate 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 LastRunTime DESC, StepID ASC
END
END
GO
EXECUTE sp_ms_marksystemobject 'sp_ViewJobListing'
I have also found that when the next_run_date is not available from the jobschedule table (because it might take up to 20 min to update), I can get it from the table sysjobactivity, as you can see on the partial list from an example below:
,[Next_Run_Date] =
CASE [jobschedule].[next_run_date]
WHEN 0 THEN (select top 1 next_scheduled_run_date from msdb.dbo.sysjobactivity WITh(NOLOCK) where job_id = [jobs].job_id order by run_requested_date desc )
ELSE CONVERT(DATETIME, CONVERT(CHAR(8), [jobschedule].[next_run_date], 112) + ' ' +
STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(8), [jobschedule].[next_run_time]), 6), 5, 0, ':'), 3, 0, ':'))
END
Best Answer
I would recommend to start by creating a staging table that will hold some information for you. The table should be constructed to hold the data the below code outputs. I recommend to store the
Schedule_ID
,name
, andjob_id
at the minimum. (If you want to cheat, you can expand the asterisks and select the columns you want, and then add the wordINTO
along with the database.schema.table_name_you_want_to_create and it will create the table for the first time for you. After that you can change it into an insert.)That code returns the schedules for all schedules and it also performs an inner join to limit the data returned to only schedules that are paired to jobs currently that are enabled.
You can then create a loop or cursor or something similar to loop through the staging table and execute the sp_update_schedule procedure. This will disable all schedules that are enabled and paired to a job. Once your maintenance is complete, you can run the loop once more, but this time enabling the schedules you had disabled earlier.
If you would like an example of a loop, you can see an example I have created in the past on stack overflow.
I have gone back and used the suggestions to create a complete code solution. Please see below, there are two scripts in total. The first will disable your jobs and the second will re-enable them. TEST THIS IN A TEST ENVIRONMENT BEFORE PUTTING IT IN PRODUCTION. Source for completeness.
Script one:
Script two