SQL Server日期逻辑 - 查找下一个提醒日期

时间:2011-06-22 19:41:13

标签: sql sql-server sql-server-2008 date

给出以下数据库表:

StartDate DATETIME  -- day that the reminder period starts
LastReminderDate DATETIME -- the last time the reminder triggered
DayOfMonth INT -- the day of the month to remind the user
Interval INT   -- how often in months to remind the user

如何根据这些值找出下一个提醒日期?例如:

StartDate = '6/1/2011'
LastReminderDate = '6/5/2011'
DayOfMonth = 5 -- remind on the 5th of the month
Interval = 2 -- remind every other month

对于此特定示例,下一个提醒日期应为2011年8月5日,因为它会在每月的第5个月提醒。我如何编写一个函数来解决这个问题?

如果LastReminderDate为NULL,那么LastReminderDate应该等于StartDate

更新:

StartDate = '6/1/2011'
LastReminderDate = NULL
DayOfMonth = 5
Interval = 2

在这种情况下,没有最后提醒日期。第一次提醒将是2011年6月5日。在这种情况下,下面的解决方案似乎返回8/5。

以下是一些具体规则:

  • 提醒应始终发生在DayOfMonth上。如果DayOfMonth在给定的月份是非法的,那么它应该是该月的最后一天。例如....如果DayOfMonth为31且下一个提醒日期将在6月31日,则应该是6月30日。
  • 下一个提醒日期应始终基于最后提醒日期加上间隔。如果“上次提醒日期”与“月日”不匹配,则可能超过间隔时间。例如......如果Last Reminder是6/1/2011并且间隔是2个月,但提醒是在本月20日,则下一个提醒将是8/20/2011。
  • 如果没有上次提醒日期,则使用开始日期而不是上次提醒日期...但这将使用将来最早的日期。如果开始日期是2011年6月1日,而日期是5,那么这将是2011年7月5日,因为今天是2011年6月22日。如果Day of Month是25,那么它将是6/25/2011

2 个答案:

答案 0 :(得分:2)

DECLARE
@StartDate AS datetime,  -- day that the reminder period starts
@LastReminderDate AS datetime, -- the last time the reminder triggered
@DayOfMonth AS integer, -- the day of the month to remind the user
@Interval AS integer   -- how often in months to remind the user

SET @StartDate = '6/1/2011'
SET @LastReminderDate = '6/5/2011'
SET @DayOfMonth = 5 -- remind on the 5th of the month
SET @Interval = 2 -- remind every other month

SELECT
CASE
   WHEN @LastReminderDate IS NULL
   THEN
     CASE WHEN Day(@StartDate) <= @DayOfMonth
       THEN DateAdd( month, ((Year( @StartDate ) - 1900) * 12) + Month( @StartDate ) - 1, @DayOfMonth - 1 )
       ELSE DateAdd( month, ((Year( @StartDate ) - 1900) * 12) + Month( @StartDate ) - 0, @DayOfMonth - 1 )
     END
  ELSE DateAdd( month, @Interval, @LastReminderDate )
END

这是最后四行,即SELECT CASE ... END陈述。我提供了一个完整的脚本,允许您插入不同的值,并查看SELECT CASE ... END对这些测试值的行为。

但是要在你的桌面上使用它,只使用最后四行(并从名称前面删除@,使它们与表的列名匹配)。

您也可以对此进行概括,以便Interval不必是几个月。如果您的表具有IntervalType列,则可以将其作为DateAdd()的第一个参数提供。请参阅文档,但有些常见的时间间隔为daysmonthsyears,等等。

EDIT2:尊重DayOfMonth。

答案 1 :(得分:0)

如果你想在没有LastReminderDate的情况下使用StartDate,那么你会想要使用COALESCE来获得那个逻辑:COALESCE(LastReminderDate, StartDate)

现在,转到上个月的最后一天:DATEADD(DAY, -DAY(COALESCE(LastReminderDate, StartDate)), COALESCE(LastReminderDate, StartDate))

最后,添加月份,然后到达我们需要的日期:

DATEADD(MONTH, Interval, DATEADD(DAY, -DAY(COALESCE(LastReminderDate, StartDate)) + DayOfMonth, COALESCE(LastReminderDate, StartDate)))

如果最后一次提醒的日期是在为提醒配置的“DayOfMonth”之后的某一天的某一天,这可能会持续不到两个月。您应该能够根据您的业务逻辑在那种情况下进行调整。