Использование sysschedules типа таблицы для событий SQL Server - PullRequest
4 голосов
/ 22 марта 2012

Я пытаюсь разработать календарь повторяющихся событий.Похоже, что таблица sysschedules в базе данных msdb вполне может справиться с этой задачей.

Однако я сталкиваюсь с несколькими трудностями, надеясь, что кто-то может помочь.это дата, когда событие должно произойти в первый раз?Или какая-либо дата в или до начала мероприятия?

b) как мне найти подходящие события (один раз, ежедневно, еженедельно, ежемесячно и т. Д.) Для определенной даты?без непосредственного использования таблицы sysschedules.Скорее создал новую таблицу с такими же столбцами.

1 Ответ

4 голосов
/ 22 марта 2012

Во-первых, вы должны ссылаться на sysschedules . Но, насколько я понимаю, это опечатка. Это

active_start_time Время в любой день между active_start_date и active_end_date этой работы начинает выполнять. Время отформатировано в формате ЧЧММСС с использованием 24-часовых часов.

следует читать как

active_start_time Время в любой день между active_start_time и active_end_time этой работой начинает выполнять. Время отформатировано в формате ЧЧММСС с использованием 24-часовых часов.

И учтите это:

active_start_date Дата, когда может начаться выполнение задания. Дата отформатирована как YYYYMMDD. NULL указывает сегодняшнюю дату.

Это означает, что если вы настраиваете повторяющееся задание на запуск каждый день каждый час и устанавливаете active_start_time = 100000 и active_start_date = 20120323, то задание не будет работать до 23 марта 2012 г. 10:00.
Но если вы создаете однократную задачу, то в этих полях указываются точная дата и время начала.

Что касается поиска подходящих событий, мое мнение следующее. Когда вы обновляете что-то существенное (например, тип расписания или время запуска) или когда повторяющееся расписание вызывает выполнение следующего задания, SQL Agent рассчитывает время следующего запуска для расписания и сохраняет его в sysjobschedules.next_run_date.

Итак, у него всегда есть список последующих выполнений, и он не решает проблему «найти подходящие события для определенной даты». И я думаю, что вы должны реализовать свою систему таким же образом.

Но если вы настаиваете на том, чтобы делать это таким образом, мы можем подумать о запросе T-SQL для этого.

UPDATE
Ниже приведен скрипт, который может помочь вам в вашей задаче. На данный момент он работает для двух типов расписания:
1. начать один раз
2. начинать ежедневно каждые N дней, один раз в день
Насколько я понимаю из вашего комментария вы будете их использовать. Вы можете добавить дополнительные типы, как только они вам понадобятся, таким же образом (UNION ALL ... UNION ALL ...).

Функция msdb_time_convert преобразует целое число ЧЧММСС в тип данных 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

Вы можете указать любую дату / время в переменной @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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...