使用 sysschedules 之类的事件表 SQL Server

use*_*409 5 sql t-sql sql-server sql-server-2008

我正在尝试开发一个经常性事件日历。看起来数据库中的sysschedulesmsdb可能会很好地完成这项工作。

但是我面临的挑战很少,希望有人能提供帮助。

a) active_start_date:这是事件第一次发生的日期吗?或者活动开始时或之前的任何日期?

b) 如何找到特定日期的匹配事件(一次、每天、每周、每月等)?

编辑:我没有直接使用sysschedules表格。而是创建了一个具有相同列的新表。

And*_*nov 5

首先,您应该参考sysschedules。但据我所知,有一个错字。这个

active_start_time作业开始执行的 active_start_date 和 active_end_date 之间的任何一天的时间。时间格式为 HHMMSS,使用 24 小时制。

应该读作

active_start_time作业开始执行的active_start_timeactive_end_time之间的任何一天的时间。时间格式为 HHMMSS,使用 24 小时制。

并考虑这一点:

active_start_date可以开始执行作业的日期。日期格式为 YYYYMMDD。NULL 表示今天的日期。

这意味着如果您将重复性作业配置为每天每小时开始并设置active_start_time = 100000 和active_start_date = 20120323,那么作业将不会运行到 2012 年 3 月 23 日上午 10 点。
但是,如果您正在创建一次性运行的任务,那么此字段将包含确切的开始日期和时间。

至于寻找匹配事件,我的意见如下。当您更新某些重要内容(例如计划类型或开始时间)或当重复计划引发下一个作业执行时,SQL 代理会计算计划的下一次运行时间并将其存储在sysjobschedules.next_run_date.

所以,它总是有一个下次执行的列表,并没有解决“找到特定日期的匹配事件”的问题。我认为你应该以同样的方式实施你的系统。

但是,如果您坚持以这种方式进行,我们可以考虑使用 T-SQL 查询。

更新
在可以帮助您完成任务的脚本下方。目前它适用于两种类型的时间表:
1. 开始一次
2. 每天开始每 N 天一次,每天一次
据我从您的评论中了解到,您将使用它们。您可以在需要时立即以相同的方式添加其他类型 ( UNION ALL ... UNION ALL ...)。

函数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
Run Code Online (Sandbox Code Playgroud)

您可以将任何日期时间指定为@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
Run Code Online (Sandbox Code Playgroud)