2012-04-06 89 views
4

假设我们有一些日期范围,例如:Rails 3中查询多个日期范围

ranges = [ 
      [(12.months.ago)..(8.months.ago)], 
      [(7.months.ago)..(6.months.ago)], 
      [(5.months.ago)..(4.months.ago)], 
      [(3.months.ago)..(2.months.ago)], 
      [(1.month.ago)..(15.days.ago)] 
     ] 

Post模型:created_at属性。

我想找到的职位,其中created_at值在此范围内,因此我们的目标是创建一个类似的查询:

SELECT * FROM posts WHERE created_at 
    BETWEEN '2011-04-06' AND '2011-08-06' OR 
    BETWEEN '2011-09-06' AND '2011-10-06' OR 
    BETWEEN '2011-11-06' AND '2011-12-06' OR 
    BETWEEN '2012-01-06' AND '2012-02-06' OR 
    BETWEEN '2012-02-06' AND '2012-03-23'; 

如果只有一个范围是这样的:

range = (12.months.ago)..(8.months.ago) 

我们可以做这个查询:

Post.where(:created_at => range) 

查询应该是:

SELECT * FROM posts WHERE created_at 
    BETWEEN '2011-04-06' AND '2011-08-06'; 

有没有办法使用这样的符号表示这个查询Post.where(:created_at => range)

什么是正确建立此查询的方法?

谢谢

回答

1

我建议你试试纯字符串形式:

# e.g. querying those in (12.months.ago .. 8.months.ago) or in (7.months.ago .. 6.months.ago) 
Post.where("(created_at <= #{12.months.ago} AND created_at >= #{8.months.ago}) OR " + 
    "(created_at <= #{7.months.ago} AND created_at >= #{6.months.ago})") 
+0

我们不需要用Arel编写sql。 – Snuggs 2015-02-11 14:28:26

7

它变得有点咄咄逼人用括号,但准备沉入AREL兔子洞

ranges = [ 
      ((12.months.ago)..(8.months.ago)), 
      ((7.months.ago)..(6.months.ago)), 
      ((5.months.ago)..(4.months.ago)), 
      ((3.months.ago)..(2.months.ago)), 
      ((1.month.ago)..(15.days.ago)) 
     ] 
table = Post.arel_table 
query = ranges.inject(table) do |sum, range| 
    condition = table[:created_at].in(range) 
    sum.class == Arel::Table ? condition : sum.or(condition) 
end 

然后,query.to_sql应该等于

(((("sessions"."created_at" BETWEEN '2011-06-05 12:23:32.442238' AND '2011-10-05 12:23:32.442575' OR "sessions"."created_at" BETWEEN '2011-11-05 12:23:32.442772' AND '2011-12-05 12:23:32.442926') OR "sessions"."created_at" BETWEEN '2012-01-05 12:23:32.443112' AND '2012-02-05 12:23:32.443266') OR "sessions"."created_at" BETWEEN '2012-03-05 12:23:32.443449' AND '2012-04-05 12:23:32.443598') OR "sessions"."created_at" BETWEEN '2012-05-05 12:23:32.443783' AND '2012-05-21 12:23:32.443938') 

而且你应该能够只是做Post.where(查询)

编辑


你也可以这样做:

range_conditions = ranges.map{|r| table[:created_at].in(r)} 
query = range_conditions.inject(range_conditions.shift, &:or) 

保持它多了几分简洁

-3

在你的情况下,我会建议使用mysql IN子句

Model.where('created_at IN (?)', ranges)