Логика даты в SQL Server - поиск следующей даты напоминания - PullRequest
1 голос
/ 22 июня 2011

Учитывая следующую таблицу базы данных:

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

В этом конкретном примере следующей датой напоминания должна быть 8/5/2011, поскольку она напоминает 5-го числа месяца каждые два месяца.Как мне написать функцию, чтобы понять это?

Если LastReminderDate равен NULL, тогда LastReminderDate должен быть равен StartDate

UPDATE:

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

В этом случаене было последней даты напоминания.Первое напоминание произойдет 5/5/2011.Решения, приведенные ниже, похоже, возвращают 8/5 в этом случае.

Вот некоторые конкретные правила:

  • Напоминание всегда должно происходить в любом DayOfMonth.Если DayOfMonth будет недопустимым для данного месяца, то это должен быть последний день этого месяца.Например .... если DayOfMonth равен 31, а следующая дата напоминания будет приходиться на 31 июня, то вместо этого она должна быть 30 июня.
  • Следующая дата напоминания всегда должна основываться на дате последнего напоминания плюсИнтервал.Если дата последнего напоминания не совпадает с днем ​​месяца, то она может быть больше, чем интервал.Например ... если последнее напоминание было 01.06.2011, а интервал составляет 2 месяца, но напоминание относится к 20 числам месяца, то следующее напоминание будет 8/20/2011.
  • Если нет последней даты напоминания, используйте дату начала вместо даты последнего напоминания ... но это будет самая ранняя дата в будущем.Если дата начала была 01.06.2011, а день месяца - 5, то это будет 07.05.2011, поскольку сегодня - 22.06.2011.Если бы Днем месяца было 25, то это было бы 6/25/2011

Ответы [ 2 ]

2 голосов
/ 22 июня 2011
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 ведет себя для этих тестовых значений.

Но чтобы просто использовать это в своей таблице, используйте только последние четыре строки (и удалите@ в начале имен, чтобы они соответствовали именам столбцов таблицы).

Вы также можете обобщить это так, чтобы интервал не составлял месяцы.Если в вашей таблице есть столбец IntervalType, вы можете указать это в качестве первого аргумента для DateAdd().См. Документы, но некоторые общие интервалы: days, months, years и т. Д.

EDIT2: Respect DayOfMonth.

0 голосов
/ 22 июня 2011

Поскольку вы хотите использовать StartDate, если LastReminderDate отсутствует, то вы захотите использовать 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», который настроен для напоминания.Вы должны быть в состоянии настроить это в зависимости от того, какова ваша бизнес-логика в этой ситуации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...