2009-06-28 58 views
4

我有一個表「用戶」列「date_of_birth」(DATE格式與日,月,年)。 在前端,我需要列出5個即將到來的生日。如何在Rails中創建「即將到來的生日」模塊?

花了年齡試圖找出邏輯..也瀏覽在谷歌沒有運氣每一個可能的文章..

任何建議,如何做到這一點的回報率?

謝謝!

+0

什麼是數據庫?如果答案是在那裏做,它會有所作爲 – 2009-06-29 00:38:13

+0

Kathy - 我會說在RoR模型中做,並避免任何數據庫特定的SQL – RichH 2009-06-29 01:48:16

回答

7

幾個答案建議計算/存儲年的一天並對其進行排序,但當靠近年底並需要考慮生日中的人時,這本身並不會很好。明年初。

我想找一個解決方案,你可以計算每個人的下一個生日的完整日期(年,月,日),然後對其進行排序。您可以在Ruby代碼中執行此操作,也可以在數據庫中使用存儲過程。後者會更快,但會讓你的應用更難以在以後遷移到不同的數據庫平臺。

只需每天更新一次即將到來的生日的列表就可以了,這意味着您可以使用某種形式的緩存。因此,需要查詢/代碼的速度是不成問題的,而且這樣的事情應該可以正常工作,只要你緩存結果:

class User 
    def next_birthday 
    year = Date.today.year 
    mmdd = date_of_birth.strftime('%m%d') 
    year += 1 if mmdd < Date.today.strftime('%m%d') 
    mmdd = '0301' if mmdd == '0229' && !Date.parse("#{year}0101").leap? 
    return Date.parse("#{year}#{mmdd}") 
    end 
end 

users = User.find(:all, :select => 'id, date_of_birth').sort_by(&:next_birthday).first(5) 

編輯:固定到閏年正常工作。

0

我會有一個before_save回調函數,用於計算並存儲數據庫中一年中的某天以及生日。

然後你有一個簡單的查詢來拉回接下來的5個生日。確保處理年底的邊界條件(我會檢查你是否在RoR中得到5個結果,然後在1月1日運行一個新的查詢以獲得一些額外的生日來彌補它到5)。

您可能需要緩存結果,以便在查詢不在公共頁面時繼續重新運行查詢。

0

我也認爲今年的日子將是一段路要走,但事實上,一年中的大部分時間都有所不同,這取決於它是否是閏年,這使得它很棘手。

更好的方法是將月份和日期存儲爲字符串:d.strftime('%m%d')。然後,您可以使用它作爲(可能)兩個查詢(假設新欄是「MONTHDAY」)

首先,

User.find(:all, 
      :condition => [:monthday > Date.now.strftime('%m%d')], 
      :select => "DISTINCT monthday", 
      :limit => 5) 

如果你沒有得到5個結果,再次進行查詢,除使用「 0101「而不是日期計算並降低限制。

這會讓你得到一個monthday字符串列表,然後你必須回到日期。

如果您想要用戶,請刪除:select行。

+0

Rich_s對before_save的評論是如何計算字符串 – 2009-06-29 02:16:03

0

如果您使用的是Oracle,您可以在不創建新列的情況下執行此操作。國際海事組織這是一種氣味來創建一個包含您已有數據的列。

這個SQL有點難看 - 我確定有一個更優雅的方法來做到這一點。通常在這些情況下,我會問我的DBA朋友的建議。

User.find(:all, 
    :conditions => 
    "TO_NUMBER(TO_CHAR(dob, 'MMDD')) >= TO_NUMBER(TO_CHAR(SYSDATE, 'MMDD'))", 
    :order => "TO_NUMBER(TO_CHAR(dob, 'MMDD'))", 
    :limit => 5) 

有些人認爲重複的列速度較快,但如果你有足夠的用戶數據速度是一個問題,您應該基準對沒有它的表中有TO_NUMBER(TO_CHAR(dob, 'MMDD'))函數索引的重複列。

+0

這是如何工作的當年的最後幾天與同一年剩餘5人的生日相比較少? – 2009-06-29 04:19:10

0

以下是我發現今天的生日:

User.find_by_sql("select * from users where date_format(date_of_birth, '%m%d') = date_format(now(), '%m%d')"

我每天運行一次。它從大約100,000行不到一秒鐘。 (它不妥善處理出生於2月29日的人)

4

由於這篇文章在我的Rails應用程序3,我使用:

u = User.where("strftime('%m%d', date_of_birth) = ?", Date.today.strftime('%m%d')) 

更新:

要在PostgreSQL使用:

u = User.where("extract(month from date_of_birth) = ? AND extract(day from date_of_birth) = ?", Date.today.strftime('%m'), Date.today.strftime('%d')) 
1

這是更好地使用SQL,使這個查詢:

next_month = (Date.today + 1.month).month # or use any other integer 

users_having_birhtday_next_month = 
    User.where("EXTRACT(MONTH FROM date_of_birth) = ?", next_month) 

注:EXTRACT - PostgreSQL的功能

0

如果你的數據庫是MySQL的,下面是可能更快:

scope :birthday_next_week, (lambda { 
    where('DayOfYear(date_of_birth) >= 7 
    And DayOfYear(date_of_birth) - DayOfYear(curdate()) Between 0 and 6) Or 
    (MOD(YEAR(curDate()),4) = 0) And MOD(YEAR(curDate()),100) != 0 
    And (DayOfYear(date_of_birth) + 366 - DayOfYear(curdate())) % 366 < 7) Or 
    (DayOfYear(date_of_birth) + 365 - DayOfYear(curdate())) % 365 < 7'). 
    order('DATE_FORMAT(date_of_birth, "%m-%d") ASC') 
}) 

編輯:改變使其在一週前的除夕/飛躍工作年份。