我目前正在处理一个调度问题,我需要能够为特定任务创建计划,其中某些任务可能具有日程参数,这些日期参数需要与计划运行时相关但我不确定这些计划应该如何存储在数据库(SQL Server)中。
例如:任务A计划在每个月的第二天运行,并且需要参数StartDate
和EndDate
的值。运行计划后,StartDate
应该是上个月的第22天,EndDate
是上个月的最后一天。
是否有任何类似的此类实现可供参考?
更新 我要问的是你如何在数据库中代表“月度第一”,“上个月”,“上个月的第2个”,“2个月前的第1个”等值,以便它可以用于计算相对于特定日期的日期。
我知道如何使用DATE函数计算这些,但这些需要在数据库中以某种方式表示并正确/有效地解析。我确信我不是第一个遇到这种情况的人。
答案 0 :(得分:0)
根据此回答here中发布的想法,我创建了以下架构和查询来计算正确的日期。
查询将转换为内联表值函数,该函数将接受@Id
和@RelativeToDate
的参数。
DayOfWeekNumber
将保持1-7的值,其中1 =星期一,7 =星期日,无论@@DATEFIRST
如何,函数都应计算正确的结果。
目前没有在表格上指定约束,但实际上必须确保表格中只存在有效的条目。
DECLARE @RelativeDate TABLE
(
Id INT IDENTITY(1,1)
, Name VARCHAR(100)
, DayOfWeekNumber TINYINT
, DayOfMonthNumber TINYINT
, LastDayOfMonth BIT
, DayOffset SMALLINT
, WeekOffset SMALLINT
, MonthOffset SMALLINT
, YearOffset SMALLINT
)
INSERT INTO @RelativeDate
(
Name
, DayOfWeekNumber
, DayOfMonthNumber
, LastDayOfMonth
, DayOffset
, WeekOffset
, MonthOffset
, YearOffset
)
VALUES
('1st of previous month', 0, 1, 'FALSE', 0, 0, -1, 0)
, ('Last of previous month', 0, 0, 'TRUE', 0, 0, -1, 0)
, ('1st of current month', 0, 1, 'FALSE', 0, 0, 0, 0)
, ('Last of current month', 0, 0, 'TRUE', 0, 0, 0, 0)
, ('7th of current month', 0, 7, 'FALSE', 0, 0, 0, 0)
, ('8th of current month', 0, 8, 'FALSE', 0, 0, 0, 0)
, ('14th of current month', 0, 14, 'FALSE', 0, 0, 0, 0)
, ('21th of current month', 0, 21, 'FALSE', 0, 0, 0, 0)
, ('22th of current month', 0, 22, 'FALSE', 0, 0, 0, 0)
, ('28th of current month', 0, 28, 'FALSE', 0, 0, 0, 0)
, ('29th of current month', 0, 29, 'FALSE', 0, 0, 0, 0)
, ('This Sunday', 7, 0, 'FALSE', 0, 0, 0, 0)
, ('Next Sunday', 7, 0, 'FALSE', 0, 1, 0, 0)
, ('Last Sunday', 7, 0, 'FALSE', 0, -1, 0, 0)
DECLARE
@Date DATE = GETDATE()
SELECT
*
, DATENAME(WEEKDAY, DateValue) AS WeekDayName
FROM
@RelativeDate
CROSS APPLY(VALUES(
DATEADD(DAY, DayOffset,
DATEADD(WEEK, WeekOffset,
DATEADD(MONTH, MonthOffset,
DATEADD(YEAR, YearOffset, @Date))))
)) AS OffsetDate(OffsetDate)
CROSS APPLY(VALUES(
CASE
WHEN LastDayOfMonth = 'TRUE'
THEN DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, OffsetDate) + 1, 0))
-- If the month doesn't have the day of the month number then return NULL
WHEN DayOfMonthNumber <> 0 AND DayOfMonthNumber > DATEPART(DAY, DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, OffsetDate) + 1, 0)))
THEN NULL
WHEN DayOfMonthNumber <> 0 AND DATEPART(DAY, OffsetDate) > DayOfMonthNumber
THEN DATEADD(DAY, DayOfMonthNumber - DATEPART(DAY, OffsetDate), OffsetDate)
WHEN DayOfMonthNumber <> 0 AND DATEPART(DAY, OffsetDate) < DayOfMonthNumber
THEN DATEADD(DAY, DayOfMonthNumber - DATEPART(DAY, OffsetDate), OffsetDate)
WHEN DayOfWeekNumber <> 0
THEN DATEADD(DAY, DayOfWeekNumber - (((DATEPART(WEEKDAY, OffsetDate) + @@DATEFIRST - 1 - 1) % 7) + 1), OffsetDate)
END
)) AS DateValue(DateValue)