【问题标题】:Rails 3 query in multiple date rangesRails 3 在多个日期范围内查询
【发布时间】:2012-04-06 10:29:09
【问题描述】:

假设我们有一些日期范围,例如:

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)]
         ]

还有一个带有:created_at 属性的Post 模型。

我想查找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) 这样的符号进行此查询?

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

谢谢

【问题讨论】:

    标签: ruby-on-rails-3 activerecord active-relation


    【解决方案1】:

    它对paren有点激进,但准备潜入兔子洞

    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(query)

    编辑


    你也可以这样做:

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

    保持简洁一点

    【讨论】:

      【解决方案2】:

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

      # 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} )" )
      

      【讨论】:

      • 我们不需要在Arel身边写sql。
      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 2012-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-31
        相关资源
        最近更新 更多