【问题标题】:How to use :conditions to compare (a datetime) with (datetime + 'number of days')?如何使用 :conditions 将(日期时间)与(日期时间 + '天数')进行比较?
【发布时间】:2010-08-28 00:25:16
【问题描述】:

我正在构建一个应用程序,用于检查用户何时需要更换他的一辆汽车的机油。以下是它的工作原理:

  1. 用户输入他的汽车名称(例如“福特野马”)
  2. 用户输入汽车一次换油的运行时间(例如 3 个月)
  3. 用户将汽车保存到数据库中
  4. 对他的所有其他汽车重复上述过程。 (是的,它是一个富有的用户;)

现在,当用户返回该站点时,他希望查看所有需要更换机油的汽车的列表。然后他更换机油并更新 'oil_changed_at' 属性。

我正在为汽车模型使用以下列:

title:string
oil_changed_at:datetime
oil_expiration_timeframe:integer

我的问题: 存储此“oil_expiration_timeframe”的首选方式是什么?当我想要获取所有需要换油的汽车的列表时,我的 :conditions 应该是什么样?

请记住,oil_expiration_timeframe 可能从几天到几年不等。它永远不会少于一天,所以我想我可以在那个字段中存储天数。但是,我不确定如何在查询中组合整数和日期时间。

【问题讨论】:

    标签: ruby-on-rails ruby datetime activerecord ruby-on-rails-3


    【解决方案1】:

    如果你索引你的 oil_changed_at 列,下面的方法是有效的。

    Car.all(:conditions => [
      "oil_changed_at > DATE_SUB(?, INTERVAL oil_expiration_timeframe day)", Time.now
    ])
    

    更好的方法是向 Car 模型添加一个新列 (next_oil_change_date) 以存储下一次换油日期并在 Car 模型更改时更新 col。

    class Car < ActiveRecord::Base
      before_save :set_next_oil_change_date
    
      def set_next_oil_change_date
        self.next_oil_change_date = next_oil_change_date + 
                                      oil_expiration_timeframe.days
      end
    end
    

    现在您可以将查询编写为:

    Car.all(:conditions => [
      "next_oil_change_date > ? ", Time.now
    ])
    

    不要忘记索引next_oil_change_date 列。

    【讨论】:

    • 感谢您的回答。像你一样,wuputah 建议我只创建一个 next_oil_change_date 列,这样我的代码就不会依赖于任何特定类型的数据库。
    【解决方案2】:

    这实际上是了解一堆 SQL 日期函数的问题。在 MySQL 中,它看起来像这样:

    :conditions => 
      "DATE_ADD(DATE(oil_changed_at),
                INTERVAL oil_expiration_timeframe DAY) <= CURDATE()"
    

    唯一的缺点是没有优化此查询的好方法。如果性能成为问题,那么在数据库中额外存储当前到期日期可能是最简单的方法。

    【讨论】:

    • 感谢您的建议。我更喜欢与数据库无关的方法,但这是一个很好的起点。
    • 我喜欢 Kandada 的查询方法(使用 DATE_SUB 代替),但我相信数据库不可知论经常被高估,除非这样做是明确的要求(一项艰巨的任务!)。我相信任何大型 Web 应用程序都需要根据他们选择的 RDBMS(和/或其他存储解决方案)来优化他们的代码。不幸的是,ANSI SQL 标准在数据库中的实现如此糟糕,但事实就是如此。
    【解决方案3】:

    向 DateTime 添加一个数字会在 Date 中添加那么多天。例如:

    irb(main):005:0> DateTime.now.to_s
    => "2010-08-27T18:32:36-06:00"
    irb(main):006:0> (DateTime.now + 7).to_s
    => "2010-09-03T18:32:48-06:00"
    

    因此,我建议您坚持将偏移量存储为天数的原始计划。

    【讨论】:

    • 是的,我知道这一点。但是我将如何在查询中使用它?我需要使用 DateTime.now (一个 Ruby 函数)和 oil_expiration_timeframe (表中的一列)进行计算。我不确定如何在 :conditions-statement 中将两者结合起来。
    【解决方案4】:

    基于 wuputah 的 MySQL 查询代码,我为 SQLite 提出了以下内容:

    :conditions => 'date(oil_changed_at, oil_expiration_timeframe||" days") <= date("now")'
    

    当然,与数据库无关的方法仍然是首选。

    【讨论】:

    • 感谢您的建议。我更喜欢与数据库无关的方法,但这是一个很好的起点。我可能会增加额外的专栏,让我的生活更轻松。我将接受 KandadaBoggu 的回答,因为它更广泛,可能会帮助其他人访问此页面,但我也非常感谢您抽出时间来回答。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-03
    • 1970-01-01
    • 2016-11-04
    • 1970-01-01
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多