Rails在时间之间进行查询,但指定术语

时间:2016-05-10 03:35:16

标签: ruby-on-rails ruby postgresql activerecord

我想查询记录但是要指定术语。例如

Home.where(created_at: Time.parse("12pm")..Time.parse("4:00pm"))

此活动记录将从中午12:00到下午4:30获取所有记录。结果将是低于记录。

id |      start_at       
---+---------------------
 1 | 2008-03-03 12:00:00
 2 | 2008-03-04 12:10:00
 3 | 2008-03-05 12:30:00
 4 | 2008-03-08 12:50:00
 5 | 2008-03-09 13:00:00
 6 | 2008-03-10 13:10:00
 7 | 2008-03-13 13:20:00
 8 | 2008-03-14 13:50:00
 9 | 2008-03-14 14:00:00
10 | 2008-03-14 14:10:00
11 | 2008-03-14 14:30:00
12 | 2008-03-14 14:50:00
13 | 2008-03-14 15:00:00
14 | 2008-03-14 15:30:00
15 | 2008-03-14 15:50:00
16 | 2008-03-14 16:00:00
17 | 2008-03-14 16:10:00

但我希望得到所有记录,但每1小时,如下面的结果。

id |      start_at       
---+---------------------
 1 | 2008-03-03 12:00:00
 5 | 2008-03-09 13:00:00
 9 | 2008-03-14 14:00:00
13 | 2008-03-14 15:00:00
16 | 2008-03-14 16:00:00

然后如何查询活动记录?感谢。

3 个答案:

答案 0 :(得分:1)

由于您选择PostgreSQL作为您的数据库,所以很幸运。使用extract函数有一种非常简单的内置方法。

Home.where("extract(hour from created_at) BETWEEN :min AND :max", min: 12, max: 16)
    .where("extract(minute from created_at) = 0")

如果这是你做了很多事情,也许稍微复杂一点的范围是有道理的:

class Home < ActiveRecord::Base
  scope :hour_range, ->(min, max){
    created_hour = Arel::Nodes::NamedFunction.new('extract', [Arel::Nodes::SqlLiteral.new('hour from "homes"."created_at"')])

    where created_hour.between(min..max)
  }

  scope :top_of_hour, ->{
    where Arel::Nodes::NamedFunction.new('extract', [Arel::Nodes::SqlLiteral.new('minute from "homes"."created_at"')]).eq(0)
  }
end

是的,简单的Arel在没有ActiveRecord DSL的情况下是丑陋的,但它的功能更强大。我已经看到很多情况下你别无选择,只能在ActiveRecord的线之外进行着色,并且知道Arel在这些情况下真的有帮助。

答案 1 :(得分:0)

试试这个

    24.times do |t|
       result = Home.where(created_at: (Date.today.beginning_of_day+ (3600*t)))
       puts result
    end

答案 2 :(得分:-1)

您可能有一个棘手的时间为此创建查询。请记住,您的数据库可能会将时间/日期值存储为整数,并且不了解1728000和1814400在不同日期的同一时间,我们可能会将其视为&#34; 2016-05-04 12 PM&#34 ;和&#34; 2016-05-05 12 PM&#34;。

根据您的数据集,我看到两个可能的选项:

  1. 创建要使用

    查询的值数组
    def query_hours(start_date, end_date, start_hour, end_hour)
      cur_date = start_date
      range = []
    
      while cur_date <= end_date
        if cur_date.hour >= start_hour && cur_date.hour <= end_hour
          range << cur_date
        end
        cur_date += 3600
      end
    
      range
    end
    
    Home.where created_at: query_hours(
      Date.new(2016, 5, 1),
      Date.new(2016, 5, 31),
      12,
      16
    )
    

    这很麻烦,如果你只是查询当天的一小部分,那么它将会非常 效率低下。但是,您可以将其优化为仅在您的设定小时范围内循环。

  2. 我猜你最好的选择,老实说,会在你的Home模型中添加created_hour属性,然后直接查询它。如果这是一个重要的查询,那么它是解决问题的最有效方法

    # in your model class
    class Home
      after_commit :update_created_hour
    
      def update_created_hour
        if created_at.minute = 0 && created_at.sec == 0
          self.created_hour = created_at.hour
        else
          self.created_hour = nil
        end
        save!
      end
    end
    
    # to query
    from = Time.parse("12pm").hour
    to = Time.parse("8pm").hour
    Home.where('created_hour >= ? AND created_hour <= ?', from, to)