2011-06-22 45 views
1

SQL Server的日期邏輯 - 尋找考慮下面的數據庫表中的下一個提醒日期

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

UPDATE:

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

在這種情況下,沒有最後提醒日期。第一次提醒將發生在2011年6月5日。下面的解決方案似乎在這種情況下返回8/5。

下面是一些具體的規則:

  • 提醒應始終對任何DAYOFMONTH是發生。如果DayOfMonth在給定的月份內是非法的,那麼它應該是該月的最後一天。例如......如果DayOfMonth是31,下一個提醒日期將在6月31日,那麼應該是6月30日。
  • 下一個提醒日期應始終基於最後提醒日期加上間隔。如果最後提醒日期與月份的日期不符,那麼它可能會超過間隔時間。例如...如果最後提醒是2011年6月1日,間隔時間是2個月,但提醒是在本月20日,則下次提醒將爲2011年8月20日。
  • 如果沒有上次提醒日期,則使用開始日期而不是上次提醒日期...但這會使用未來最早的日期。如果開始日期是2011年6月1日,而月中的某天是5,那麼2011年7月5日以後這將是2011年7月5日。如果月的一天是25那麼這將是2011年6月25日
+1

如果開始日期是2011年6月14日而DayOfMonth = 7應該是2011年7月7日或2011年6月7日如果DayOfMonth = 31應該怎麼辦它假定每月的第一天或最後一天還是應該炸燬?您需要讓我們知道規則是什麼,而不是僅僅挑選輸入和輸出值 –

回答

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()。請參閱文檔,但一些常見區間爲daysmonths,years等。

EDIT2:尊重DayOfMonth。

+0

嗯,他對我的答案和目前提供的其他答案進行了投票,以及爲什麼? –

+0

仍然看起來不正確。現在如果LastReminder爲NULL,它給出8/1/2011 – Dismissile

+0

也許有不同的方式來思考它......但基本上計算通常很容易。您將始終可以將X個月添加到LastReminder日期以獲取下一個提醒日期。唯一的問題是,當你沒有最後提醒日期時,你必須弄清楚第一個提醒日期將會是什麼。這就是我說使用StartDate的原因。 LastReminderDate應該/將永遠是我想要的月份的同一天。這只是試圖找出第一次提醒他們,當這不存在。這有意義嗎? – Dismissile

0

既然你要使用的起始日期,如果沒有LastReminderDate,那麼你需要使用聚結邏輯的該位: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))) 

這將潛在地往前走了不到兩個月,如果最後提醒的日期是在本月的前一天,「 DayOfMo nth「配置爲提醒。你應該能夠調整這取決於你的業務邏輯是在這種情況下。

+0

當LastReminderDate是2011年8月1日這不起作用 - 它給我10/2011/2011而不是2011年8月5日 – Dismissile

+0

@Dismissle你應該更新你的問題,然後因爲它真的不清楚爲什麼這將是 –

+0

這可能是一個不好的例子。看到我對格雷格H的回答的評論。本質上,我將始終能夠將間隔添加到LastReminderDate。如果不存在,那麼我需要確定第一個提醒日期應該基於開始日期。如果開始日期是2011年6月1日,那麼它應該是2011年6月5日的第一次提醒。如果是2011年6月6日,那麼它應該是7/5/2011。合理? – Dismissile

相關問題