简体   繁体   English

使用 sysschedules 之类的事件表 SQL 服务器

[英]Using sysschedules like table for events SQL Server

I am trying to develop a recurring event calendar.我正在尝试开发一个定期事件日历。 Looks like the sysschedules table in the msdb database might do the job just fine.看起来msdb数据库中的sysschedules表可以很好地完成这项工作。

However I am facing few challenges, hoping somebody could help.但是我面临的挑战很少,希望有人可以提供帮助。

a) active_start_date : is this the date first time an event supposed to occur? a) active_start_date :这是第一次发生事件的日期吗? Or any date on or before the event start?或者活动开始之前或之前的任何日期?

b) how can I find the matching events (once, daily, weekly, monthly etc) for a specific date? b) 我怎样才能找到特定日期的匹配事件(一次、每天、每周、每月等)?

Edit: I am not directly using the sysschedules table.编辑:我没有直接使用sysschedules表。 Rather created a new table with same columns.而是创建了一个具有相同列的新表。

First, you should refer sysschedules . 首先,你应该参考sysschedules But as far as I understand there is a typo. 但据我所知,有一个错字。 This 这个

active_start_time Time on any day between active_start_date and active_end_date that job begins executing. active_start_time作业开始执行的active_start_date和active_end_date之间的任何一天的时间。 Time is formatted HHMMSS, using a 24-hour clock. 时间格式为HHMMSS,使用24小时制。

should be read as 应该读作

active_start_time Time on any day between active_start_time and active_end_time that job begins executing. active_start_time作业开始执行的active_start_timeactive_end_time之间的任何一天的时间。 Time is formatted HHMMSS, using a 24-hour clock. 时间格式为HHMMSS,使用24小时制。

And consider this: 考虑一下:

active_start_date Date on which execution of a job can begin. active_start_date可以开始执行作业的日期。 The date is formatted as YYYYMMDD. 日期格式为YYYYMMDD。 NULL indicates today's date. NULL表示今天的日期。

That means if you configure recurring job to start every day every hour and set active_start_time = 100000 and active_start_date = 20120323 then job won't run till 23 March 2012 10 AM. 这意味着如果您将定期作业配置为每小时每天开始并设置active_start_time = 100000和active_start_date = 20120323,那么作业将不会运行到2012年3月23日上午10点。
But if you're creating once-running task then this fields are containing exact start date and time. 但是,如果您正在创建一次运行的任务,则此字段包含确切的开始日期和时间。

As for finding matching events, my opinion is following. 至于寻找匹配事件,我的意见如下。 When you update something significant (ex. schedule type or start time) or when recurring schedule raises next job execution SQL Agent calculates next run time for the schedule and stores it in sysjobschedules.next_run_date . 当您更新重要事项(例如计划类型或开始时间)或重复计划提高下一个作业执行时,SQL Agent计算计划的下一个运行时间并将其存储在sysjobschedules.next_run_date

So, it always has a list of next time executions, and doesn't solve the problem "find the matching events for a specific date". 因此,它总是有一个下一次执行的列表,并没有解决问题“找到特定日期的匹配事件”。 And I think you should implement your system in the same way. 我认为你应该以同样的方式实现你的系统。

But if you insist on doing it in such manner we can think about T-SQL query for that. 但是如果你坚持以这种方式做到这一点,我们可以考虑T-SQL查询。

UPDATE UPDATE
Below the script that can help you with your task. 脚本下方可以帮助您完成任务。 At the moment it works for two types of schedule: 目前它适用于两种类型的计划:
1. start once 1.开始一次
2. start daily every N days, once at the day 2.每天开始,每天一次,每天一次
As far as I understand from your comment you'll use them. 据我所知,你会使用它们。 You can add additional types as soon as you need them in the same manner ( UNION ALL ... UNION ALL ... ). 您可以在需要时以相同的方式添加其他类型( UNION ALL ... UNION ALL ... )。

Function msdb_time_convert converts HHMMSS integer into TIME datatype. 函数msdb_time_convert将HHMMSS整数转换为TIME数据类型。

CREATE FUNCTION msdb_time_convert (
    @int_time INT
)
RETURNS TIME(0)
AS 
BEGIN
    IF NOT (@int_time BETWEEN 0 AND 235959) 
        RETURN NULL

    DECLARE @str VARCHAR(32) = CAST(@int_time AS VARCHAR(32))
    SELECT @str = REPLICATE('0', 6 - LEN(@str)) + @str
    SELECT @str = STUFF(@str, 3, 0, ':')
    SELECT @str = STUFF(@str, 6, 0, ':')

    RETURN CONVERT(TIME(0), @str, 108)
END
GO

You can specify any datetime into @find_date variable to find next runs at different points of time. 您可以在@find_date变量中指定任何日期@find_date以查找在不同时间点的下一次运行。

DECLARE @find_date DATETIME = GETDATE()

;WITH CTE AS (
    SELECT 
        CONVERT(DATE, CAST(active_start_date AS VARCHAR(32)), 112) AS active_start_date, 
        CONVERT(DATE, CAST(active_end_date AS VARCHAR(32)), 112) AS active_end_date, 
        dbo.msdb_time_convert(active_start_time) AS active_start_time,
        dbo.msdb_time_convert(active_end_time) AS active_end_time,  
        schedule_id,
        schedule_uid,
        name,
        enabled,
        freq_type,
        freq_interval,
        freq_subday_type,
        freq_subday_interval,
        freq_relative_interval,
        freq_recurrence_factor,
        CAST(@find_date AS DATE) AS today_date,
        CAST(@find_date AS TIME(0)) AS today_time,
        DATEADD(day, DATEDIFF(day, CONVERT(DATETIME, CAST(active_start_date AS VARCHAR(32)), 112) - 1, @find_date) % NULLIF(freq_interval, 0), CAST(@find_date AS DATE)) AS next_daily_day
    FROM dbo.sysschedules
)
SELECT 
    schedule_id,
    name,
    CAST(active_start_date AS DATETIME) + active_start_time AS next_run_datetime
FROM CTE
WHERE
    enabled = 1
    AND freq_type = 1       -- 1 = One time only
    AND CAST(active_start_date AS DATETIME) + active_start_time >= @find_date

UNION ALL

SELECT 
    schedule_id,
    name,
    DATEADD(
        DAY,
        CASE WHEN CAST(next_daily_day AS DATETIME) + active_start_time > @find_date THEN 0 ELSE freq_interval END,
        CAST(next_daily_day AS DATETIME) + active_start_time 
    ) AS next_run_datetime
FROM CTE 
WHERE
    enabled = 1
    AND freq_type = 4                   -- 4 = Daily (Every freq_interval days)
    AND freq_subday_type = 1            -- 1 = At the specified time
    AND CAST(active_end_date AS DATETIME) + active_end_time >= @find_date

Everyone is working way too hard on this.每个人都在这方面工作太努力了。 You can convert an HHHmmss-looking "seconds" integer to total seconds without converting int-to-string-to-int, and cast the date as a string for implicit date math:您可以将看起来像 HHHmmss 的“秒”integer 转换为总秒数,而无需将 int-to-string-to-int 转换为整数,并将日期转换为隐式日期数学的字符串:

select dateadd(s, next_run_time - ((next_run_time / 100) * 40) - ((next_run_time / 10000) * 2400), str(next_run_date))
from msdb..sysjobschedules

(subtracting out 40 seconds per minute and 40*100 + 2400 seconds per hour.) (减去每分钟 40 秒和每小时 40*100 + 2400 秒。)

Or, define a function:或者,定义一个 function:

CREATE FUNCTION fn_JobSeconds (@hhhmmss int) --digits interpreted as HHHmmss
RETURNS int AS 
BEGIN 
    return @hhhmmss - ((@hhhmmss / 100) * 40) - ((@hhhmmss / 10000) * 2400)
END

select dateadd(s, dbo.fn_JobSeconds(next_run_time), str(next_run_date))
from msdb..sysjobschedules

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM