2009-06-28 87 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') 
}) 

编辑:改变使其在一周前的除夕/飞跃工作年份。

相关问题