use*_*409 5 sql t-sql sql-server sql-server-2008
我正在尝试开发一个经常性事件日历。看起来数据库中的sysschedules表msdb可能会很好地完成这项工作。
但是我面临的挑战很少,希望有人能提供帮助。
a) active_start_date:这是事件第一次发生的日期吗?或者活动开始时或之前的任何日期?
b) 如何找到特定日期的匹配事件(一次、每天、每周、每月等)?
编辑:我没有直接使用sysschedules表格。而是创建了一个具有相同列的新表。
首先,您应该参考sysschedules。但据我所知,有一个错字。这个
active_start_time作业开始执行的 active_start_date 和 active_end_date 之间的任何一天的时间。时间格式为 HHMMSS,使用 24 小时制。
应该读作
active_start_time作业开始执行的active_start_time和active_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)