Schedule SQL Job in a user configured time intervals everyday
Asked Answered
E

5

6

In my application (ASP.NET, C#), i need to run a stored procedure in a set of pre defined time interval(s) everyday. So that i created a sql job and scheduled the same. But the problem is, there is a option to create/modify this time intervals using the application and this will store the modified time intervals in a table. So i need to run the stored procedure in the user configured time intervals.

Now i am doing the following steps to resolve the issue.

  1. Created a job to execute the stored procedure and scheduled for every 1 min.
  2. Inside the stored procedure i will check the current time (min) and the scheduled interval(s).
  3. If it is matched then the tsql code part inside the stored procedure will execute, other wise skip the process.

This is working fine, but the stored procedure will execute every minute (Hope somebody faced the same issue).

Looking for a better solution to solve this issue .

Euphroe answered 15/4, 2016 at 4:33 Comment(11)
@HumbleGrendel , Using the application user can Change existing time intervals, create new intervals and delete the existing intervals.Euphroe
Is there a problem with executing the SP every minute? probably not. It seems like a good idea to me.Yoshi
@Nick.McDermaid, thank you. I have one more solution for this. That is, once the time intervals is changed by the application user then the schedules also create/edit/delete based on the new time intervals using the TSQL script from inside the CRUD SPs of time interval table. I think it is better than executing the SP each and every minute. Suggestion plz.Euphroe
If users are modifying your time interval table (TID) only by SP[s] you've created or you can change, this SP[s] is the best place to control jobs and shedules which TID defines.Simoom
@I_am_Batman, please read the comments, scheduler/job will execute in a predefined static time intervals. In my case user can modify this intervals at any time. And in my 1st point , already mentioned am using a scheduled job itself. (Created a job to execute the stored procedure and scheduled for every 1 min.)Euphroe
That 1 minute thing is what I'm unable to grasp. Why can't we start the scheduler at the given time interval? For e.g, why can't we invoke the scheduler at say 8PM? Why do we have to create scheduler at hit everytime till it's 8?Cosine
@I_am_Batman, Application end user can create/modify multiple time interval(s), i need to schedule this SP on that intervals. Every-time the end user created/modified the time intervals i need to reschedule my SP based on that time intervals. Hope it is clear (Mine English is not excellent)Euphroe
You could dynamically recreate the scheduler/procedure, everytime the changes are required, by passing new time/interval as parameters. Sorry, I'm answering from Oracle perspective. We have a dbms_scheduler package, and I had dynamically altered the time as per user requirement. Tsql is not my forte. But there should be something similar.Cosine
That is, once the time intervals is changed by the application user then the schedules also create/edit/delete based on the new time intervals using the TSQL script from inside the CRUD SPs of time interval table. I think it is better than executing the SP each and every minute. rgt?Euphroe
That is what, I feel, should be done.Cosine
Let us continue this discussion in chat.Euphroe
T
3

First thing needed is a little stored procedure for creating interval schedules.

USE msdb
GO 

CREATE PROCEDURE spCreateSchedule_Interval 
    @scheduleName NVARCHAR(255),
    @intervalType VARCHAR(255),     -- one of 'seconds', 'minutes', 'hours'
    @interval int,
    @ScheduleId int OUT
AS
BEGIN
    -- determine time interval
    DECLARE @intervalTypeInt INT;
    IF @intervalType = 'seconds'
        SET @intervalTypeInt = 2;
    ELSE IF @intervalType = 'minutes'
        SET @intervalTypeInt = 4;
    ELSE IF @intervalType = 'hours'
        SET @intervalTypeInt = 8;

    EXEC msdb.dbo.sp_add_jobschedule 
        @job_name='NameOfTheJobToBeApplied', -- or you can use @job_id instead
        @name=@scheduleName,        -- you can later find the schedule to update/delete using this name, or the @ScheduleId
        @enabled=1, 
        @freq_type=4,               -- daily
        @freq_interval=1,           -- every day
        @freq_subday_type=@intervalTypeInt, -- eg. 2 = seconds
        @freq_subday_interval=@interval,    -- eg. 15 - run every 15 seconds
        @freq_relative_interval=0, 
        @freq_recurrence_factor=0, 
        @active_start_date=20160101, -- some date in the past to activate immediately, or put some date in the future for delay
        @active_end_date=99991231,  -- never end, or specify some valid date
        @active_start_time=000000,  -- active from 00:00:00 - caution: when creating multiple schedules use different time here, eg 000001, 000002, so that they not get started simultanously, as it might couse some errrors
        @active_end_time=235959,    -- active to 23:59:59
        @schedule_id=@ScheduleID    -- this will output the newly generated id, which can be used later to localize the schedule for update/delete
END;
GO

Example usage:

DECLARE @ScheduleId int;
    EXEC spCreateSchedule_Interval 
        @scheduleName = 'UserA_Schedule',
        @intervalType = 'minutes',
        @interval = 27,
        @ScheduleId = @ScheduleId OUT;

This should create schedule to run every 27 minutes.

You can also need a proc for creating a schedule for specific time:

CREATE PROCEDURE spCreateSchedule_ExactTime
    @scheduleName NVARCHAR(255),
    @timeToRun TIME,
    @ScheduleId int OUT
AS
BEGIN

    DECLARE @StartTime INT;
    SET @StartTime = DATEPART(hour, @timeToRun) * 10000 + DATEPART(minute, @timeToRun) * 100 + DATEPART(second, @timeToRun);

    EXEC msdb.dbo.sp_add_jobschedule 
        @job_name='NameOfTheJobToBeApplied', -- or you can use @job_id instead
        @name=@scheduleName,        -- you can later find the schedule to update/delete using this name, or the @ScheduleId
        @enabled=1, 
        @freq_type=4,               -- daily
        @freq_interval=1,           -- every day
        @freq_subday_type=1,        -- At the specified time
        @freq_subday_interval=1,    -- once a day, probably not used
        @freq_relative_interval=0, 
        @freq_recurrence_factor=0, 
        @active_start_date=20160101,    -- some date in the past to activate immediately, or put some date in the future for delay
        @active_end_date=99991231,      -- never end, or specify some valid date
        @active_start_time=@StartTime,  -- active from 00:00:00 - caution: when creating multiple schedules use different time here, eg 000001, 000002, so that they not get started simultanously, as it might couse some errrors
        @active_end_time=235959,        -- active to 23:59:59
        @schedule_id=@ScheduleID        -- this will output the newly generated id, which can be used later to localize the schedule for update/delete
END;
GO

Example usage:

DECLARE @ScheduleId INT;
    EXEC spCreateSchedule_ExactTime 
        @scheduleName = 'UserB_Schedule',
        @timeToRun = '14:58:00',
        @ScheduleId = @ScheduleId OUT;

This should create schedule to run every day at 14:58.

The above two procedures might be easily merged into one. Separated here for clarity and ease of maintenance. They can also be further enhanced, you can parametrize the @freq_type, @freq_interval etc. All you need is in the documentation: https://msdn.microsoft.com/pl-pl/library/ms366342(v=sql.110).aspx

Another step are procedures for updating existing schedules:

CREATE PROCEDURE spUpdateSchedule_Interval
    @scheduleName NVARCHAR(255),
    @intervalType VARCHAR(255),     -- one of 'seconds', 'minutes', 'hours'
    @interval int
    --, @ScheduleId int -- you can use this instead of the firs param

AS
BEGIN
    -- determine time interval
    DECLARE @intervalTypeInt INT;
    IF @intervalType = 'seconds'
        SET @intervalTypeInt = 2;
    ELSE IF @intervalType = 'minutes'
        SET @intervalTypeInt = 4;
    ELSE IF @intervalType = 'hours'
        SET @intervalTypeInt = 8;

    EXEC msdb.dbo.sp_update_schedule  
        --@schedule_id=@ScheduleID, -- you can use this instead of the line below, if you change the proc parameter
        @name=@scheduleName,        
        --@new_name = @newName      -- if you want to change the schedule name
        @enabled=1, 
        @freq_type=4,               -- daily
        @freq_interval=1,           -- every day
        @freq_subday_type=@intervalTypeInt, -- eg. 2 = seconds
        @freq_subday_interval=@interval,    -- eg. 15 - run every 15 seconds
        @freq_relative_interval=0, 
        @freq_recurrence_factor=0, 
        @active_start_date=20160101, -- some date in the past to activate immediately, or put some date in the future for delay
        @active_end_date=99991231,  -- never end, or specify some valid date
        @active_start_time=000000,  -- active from 00:00:00 - caution: when creating multiple schedules use different time here, eg 000001, 000002, so that they not get started simultanously, as it might couse some errrors
        @active_end_time=235959 -- active to 23:59:59
END;
GO

And the usage:

EXEC spUpdateSchedule_Interval 
    @scheduleName = 'UserB_Schedule',
    @intervalType = 'minutes',
    @interval = 25;
GO

You should now be able to create spUpdateSchedule_ExactTime by analogy.

The last thing you need - a stored procedure for deleting schedules:

USE msdb
GO 

CREATE PROCEDURE spDeleteSchedule 
    @scheduleName VARCHAR(255)
AS
BEGIN
    EXEC msdb.dbo.sp_delete_schedule @schedule_name = @scheduleName, @force_delete = 1;
END;
GO

And its usage:

USE msdb
GO 

EXEC spDeleteSchedule 'UserA_Schedule';

Or you can easily write alternative which will use schedule_id instead of schedule_name (sp_delete_schedule can get either of those).

NOTICE: In updating and deleting procedures you can use either names or IDs for identifying schedules. While names are more human friendly, and I used them for the examples to be easier to follow, I strongly recommend that you use IDs instead. Names are not forced to be unique, so if you happen to create two schedules with the same name, then both delete and update procs will fail, unless you use schedule_id as a parameter.

Tentmaker answered 27/4, 2016 at 8:11 Comment(0)
J
4

Assuming this isn't a frequent event, execute sp_update_schedule when the table is updated. Add this to the update procedure or as a trigger if directly updating the table.

Jaime answered 15/4, 2016 at 5:3 Comment(1)
Than you @HumbleGrendel , Using the application user can Change existing time intervals, create new intervals and delete the existing intervals. And i need to schedule this job for everyday in a specified time intervals (eg: - Everyday 8 PM, 10 PM, 11:30 PM). Is this can we solve using execute sp_update_schedule ?Euphroe
L
3

1 Create a sql job and create step 1 (to exec your sp) https://msdn.microsoft.com/en-in/library/ms190268.aspx#Anchor_2

2 . Add multiple schedules to the job as per requirement (using sp_add_jobschedule) . details : https://msdn.microsoft.com/en-us/library/ms366342.aspx.

Lack answered 26/4, 2016 at 3:29 Comment(1)
Note In case you requirement is update existing schedule use sp_update_schedule (msdn.microsoft.com/en-us/library/ms187354.aspx) In case you requirement is update existing schedule use sp_delete_schedule (msdn.microsoft.com/en-us/library/ms175050.aspx)Lack
H
3

It is good that scheduler time is being manage by application.

But in real world, why user will keep updating scheduler time? I mean to say the frequency.

So I think whenever time is modified from application then fire this new stored procedure which will update the scheduler time using sp_update_schedule.

There is no reason for the stored procedure to execute every minute. It will only fire when scheduler is modified via application.

Hayne answered 26/4, 2016 at 4:52 Comment(0)
T
3

First thing needed is a little stored procedure for creating interval schedules.

USE msdb
GO 

CREATE PROCEDURE spCreateSchedule_Interval 
    @scheduleName NVARCHAR(255),
    @intervalType VARCHAR(255),     -- one of 'seconds', 'minutes', 'hours'
    @interval int,
    @ScheduleId int OUT
AS
BEGIN
    -- determine time interval
    DECLARE @intervalTypeInt INT;
    IF @intervalType = 'seconds'
        SET @intervalTypeInt = 2;
    ELSE IF @intervalType = 'minutes'
        SET @intervalTypeInt = 4;
    ELSE IF @intervalType = 'hours'
        SET @intervalTypeInt = 8;

    EXEC msdb.dbo.sp_add_jobschedule 
        @job_name='NameOfTheJobToBeApplied', -- or you can use @job_id instead
        @name=@scheduleName,        -- you can later find the schedule to update/delete using this name, or the @ScheduleId
        @enabled=1, 
        @freq_type=4,               -- daily
        @freq_interval=1,           -- every day
        @freq_subday_type=@intervalTypeInt, -- eg. 2 = seconds
        @freq_subday_interval=@interval,    -- eg. 15 - run every 15 seconds
        @freq_relative_interval=0, 
        @freq_recurrence_factor=0, 
        @active_start_date=20160101, -- some date in the past to activate immediately, or put some date in the future for delay
        @active_end_date=99991231,  -- never end, or specify some valid date
        @active_start_time=000000,  -- active from 00:00:00 - caution: when creating multiple schedules use different time here, eg 000001, 000002, so that they not get started simultanously, as it might couse some errrors
        @active_end_time=235959,    -- active to 23:59:59
        @schedule_id=@ScheduleID    -- this will output the newly generated id, which can be used later to localize the schedule for update/delete
END;
GO

Example usage:

DECLARE @ScheduleId int;
    EXEC spCreateSchedule_Interval 
        @scheduleName = 'UserA_Schedule',
        @intervalType = 'minutes',
        @interval = 27,
        @ScheduleId = @ScheduleId OUT;

This should create schedule to run every 27 minutes.

You can also need a proc for creating a schedule for specific time:

CREATE PROCEDURE spCreateSchedule_ExactTime
    @scheduleName NVARCHAR(255),
    @timeToRun TIME,
    @ScheduleId int OUT
AS
BEGIN

    DECLARE @StartTime INT;
    SET @StartTime = DATEPART(hour, @timeToRun) * 10000 + DATEPART(minute, @timeToRun) * 100 + DATEPART(second, @timeToRun);

    EXEC msdb.dbo.sp_add_jobschedule 
        @job_name='NameOfTheJobToBeApplied', -- or you can use @job_id instead
        @name=@scheduleName,        -- you can later find the schedule to update/delete using this name, or the @ScheduleId
        @enabled=1, 
        @freq_type=4,               -- daily
        @freq_interval=1,           -- every day
        @freq_subday_type=1,        -- At the specified time
        @freq_subday_interval=1,    -- once a day, probably not used
        @freq_relative_interval=0, 
        @freq_recurrence_factor=0, 
        @active_start_date=20160101,    -- some date in the past to activate immediately, or put some date in the future for delay
        @active_end_date=99991231,      -- never end, or specify some valid date
        @active_start_time=@StartTime,  -- active from 00:00:00 - caution: when creating multiple schedules use different time here, eg 000001, 000002, so that they not get started simultanously, as it might couse some errrors
        @active_end_time=235959,        -- active to 23:59:59
        @schedule_id=@ScheduleID        -- this will output the newly generated id, which can be used later to localize the schedule for update/delete
END;
GO

Example usage:

DECLARE @ScheduleId INT;
    EXEC spCreateSchedule_ExactTime 
        @scheduleName = 'UserB_Schedule',
        @timeToRun = '14:58:00',
        @ScheduleId = @ScheduleId OUT;

This should create schedule to run every day at 14:58.

The above two procedures might be easily merged into one. Separated here for clarity and ease of maintenance. They can also be further enhanced, you can parametrize the @freq_type, @freq_interval etc. All you need is in the documentation: https://msdn.microsoft.com/pl-pl/library/ms366342(v=sql.110).aspx

Another step are procedures for updating existing schedules:

CREATE PROCEDURE spUpdateSchedule_Interval
    @scheduleName NVARCHAR(255),
    @intervalType VARCHAR(255),     -- one of 'seconds', 'minutes', 'hours'
    @interval int
    --, @ScheduleId int -- you can use this instead of the firs param

AS
BEGIN
    -- determine time interval
    DECLARE @intervalTypeInt INT;
    IF @intervalType = 'seconds'
        SET @intervalTypeInt = 2;
    ELSE IF @intervalType = 'minutes'
        SET @intervalTypeInt = 4;
    ELSE IF @intervalType = 'hours'
        SET @intervalTypeInt = 8;

    EXEC msdb.dbo.sp_update_schedule  
        --@schedule_id=@ScheduleID, -- you can use this instead of the line below, if you change the proc parameter
        @name=@scheduleName,        
        --@new_name = @newName      -- if you want to change the schedule name
        @enabled=1, 
        @freq_type=4,               -- daily
        @freq_interval=1,           -- every day
        @freq_subday_type=@intervalTypeInt, -- eg. 2 = seconds
        @freq_subday_interval=@interval,    -- eg. 15 - run every 15 seconds
        @freq_relative_interval=0, 
        @freq_recurrence_factor=0, 
        @active_start_date=20160101, -- some date in the past to activate immediately, or put some date in the future for delay
        @active_end_date=99991231,  -- never end, or specify some valid date
        @active_start_time=000000,  -- active from 00:00:00 - caution: when creating multiple schedules use different time here, eg 000001, 000002, so that they not get started simultanously, as it might couse some errrors
        @active_end_time=235959 -- active to 23:59:59
END;
GO

And the usage:

EXEC spUpdateSchedule_Interval 
    @scheduleName = 'UserB_Schedule',
    @intervalType = 'minutes',
    @interval = 25;
GO

You should now be able to create spUpdateSchedule_ExactTime by analogy.

The last thing you need - a stored procedure for deleting schedules:

USE msdb
GO 

CREATE PROCEDURE spDeleteSchedule 
    @scheduleName VARCHAR(255)
AS
BEGIN
    EXEC msdb.dbo.sp_delete_schedule @schedule_name = @scheduleName, @force_delete = 1;
END;
GO

And its usage:

USE msdb
GO 

EXEC spDeleteSchedule 'UserA_Schedule';

Or you can easily write alternative which will use schedule_id instead of schedule_name (sp_delete_schedule can get either of those).

NOTICE: In updating and deleting procedures you can use either names or IDs for identifying schedules. While names are more human friendly, and I used them for the examples to be easier to follow, I strongly recommend that you use IDs instead. Names are not forced to be unique, so if you happen to create two schedules with the same name, then both delete and update procs will fail, unless you use schedule_id as a parameter.

Tentmaker answered 27/4, 2016 at 8:11 Comment(0)
T
2

I am not sure how your application or user code works, but you can fire a trigger to the SQL Agent from your user code to start the job by calling https://msdn.microsoft.com/nl-nl/library/ms186757.aspx. The only limitation is that the user needs to be owner of the job or a member of sysadmin, see the link for more details.

Tramel answered 15/4, 2016 at 6:6 Comment(3)
Thank you, but i need to schedule this job for everyday in a specified time intervals (eg: - Everyday 8 PM, 10 PM, 11:30 PM).Euphroe
In that case, why not just attaching to 3 schedules? Or did I miss something ?Tramel
Using the application user can Change existing time intervals, create new intervals and delete the existing intervals. And i need to schedule this job for everyday in the specified time intervals configured by application users. Also application users can change it anytime this time intervals, so ( i think ) once its is changed by the application user then the schedules also create/edit/delete based on the new time intervals.Euphroe

© 2022 - 2025 — McMap. All rights reserved.