将相对日期值存储在数据库中

时间:2015-02-11 15:23:51

标签: sql-server date scheduled-tasks relative

我目前正在处理一个调度问题,我需要能够为特定任务创建计划,其中某些任务可能具有日程参数,这些日期参数需要与计划运行时相关但我不确定这些计划应该如何存储在数据库(SQL Server)中。

例如:任务A计划在每个月的第二天运行,并且需要参数StartDateEndDate的值。运行计划后,StartDate应该是上个月的第22天,EndDate是上个月的最后一天。

是否有任何类似的此类实现可供参考?

更新 我要问的是你如何在数据库中代表“月度第一”,“上个月”,“上个月的第2个”,“2个月前的第1个”等值,以便它可以用于计算相对于特定日期的日期。

我知道如何使用DATE函数计算这些,但这些需要在数据库中以某种方式表示并正确/有效地解析。我确信我不是第一个遇到这种情况的人。

1 个答案:

答案 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)