Ruby on rails 使用.where on实例方法搜索日期范围
我有一个名为Runs的模型,这里有两个实例来展示它的外观:Ruby on rails 使用.where on实例方法搜索日期范围,ruby-on-rails,ruby,activerecord,Ruby On Rails,Ruby,Activerecord,我有一个名为Runs的模型,这里有两个实例来展示它的外观: <Run id: 138, route_id: 1, leave_date: "2018-07-17 08:00:00", left: false, returned: false, created_at: "2018-07-17 14:08:28", updated_at: "2018-07-17 14:08:28", distance: nil, transport_time: nil> <Run id: 139,
<Run id: 138, route_id: 1, leave_date: "2018-07-17 08:00:00", left: false, returned: false, created_at: "2018-07-17 14:08:28", updated_at: "2018-07-17 14:08:28", distance: nil, transport_time: nil>
<Run id: 139, route_id: 1, leave_date: "2018-07-18 09:00:00", left: false, returned: false, created_at: "2018-07-17 14:08:28", updated_at: "2018-07-17 14:08:28", distance: nil, transport_time: nil>
它提供了日期时间,例如:
Run.first.delivery_date
返回
Tue, 17 Jul 2018 09:00:00 UTC +00:00
如果可能,我想使用.where选择日期与特定日期匹配的跑步。通常我会使用如下内容,但它仅适用于模型的属性(如leave_date),而不适用于实例方法(如delivery_date):
Run.where('delivery_date BETWEEN ? AND ?', date.beginning_of_day, date.end_of_day)
如何执行此选择?
非常感谢。您可以使用选择方法:
Run.all.select { |r| r.delivery_date.in?(date.beginning_of_day..date.end_of_day) }
但如果你跑得太多,效率就不高了
我建议将交货日期数据保存在名为交货日期的表列中,并在数据库端过滤记录:
Run.where(delivery_date: date.beginning_of_day..date.end_of_day)
没有机会从数据库查询中调用ruby方法。而且,这并没有任何原因,因为看起来和ruby迭代一样。但是您可以在数据库查询中为您的ruby方法编写一个简单的类似函数。 试着这样做:
Run.joins(:routes)
.where("runs.leave_date + interval '1 day' * routes.delivery_working_day_offset BETWEEN ? AND ?',
date.beginning_of_day, date.end_of_day)
这个例子忽略了周末和工作日之间的区别。但是关于如何在数据库查询中编写business_days函数的例子太多了
最简单的解决方案:将交付日期保存到一个数据库表中。为什么不将此属性作为列保留在数据库中,然后对其进行查询?您只能使用ActiveRecord查询sql列,不能查询计算值。这完全是您问题的旁注,但我建议使用列名,如leaves\u at,而不是leave\u date。按照惯例,以_结尾的列名是日期时间字段,而以_结尾的列则是日期字段。您的leave_date列实际上是一个datetime,因此是一个容易混淆的名称。如果它是一个日期字段,我会将其称为leaves_on。类似地,您可以有一个新列:delivery_at,它在保存记录时计算并保存。然后,您可以使用SQL执行上述查询,这正是您通常会执行的方式。不过,您需要注意的唯一一件事是,例如,route.delivery\u working\u day\u偏移量是否会发生变化-在这种情况下,您需要在所有相关的运行中重新计算delivery\u at。如上所述,请注意,这不会在SQL中执行查询,因此不会扩展;如果runs表变大,性能将非常糟糕。
Run.all.select { |r| (date.beginning_of_day..date.end_of_day).include?(r.delivery_date) }
Run.joins(:routes)
.where("runs.leave_date + interval '1 day' * routes.delivery_working_day_offset BETWEEN ? AND ?',
date.beginning_of_day, date.end_of_day)