内部两个日期之间的轨道差异.where

时间:2017-11-06 23:24:12

标签: mysql ruby-on-rails ruby-on-rails-4

这是我的逻辑 我希望将最近的4个更昂贵的手机送到特定的手机@mobile,但在一种情况下,这两款手机的发布日期之间的差异不会超过一年半 这是查询

high = Mobile.where("price >= #{@mobile.price} AND id != #{@mobile.id} AND visible = true").where("ABS(release_date - #{@mobile.release_date}) > ?", 18.months).order(price: :ASC).first(4)

第一个.where()工作正常,但第二个不工作,我收到此错误

Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '00:00:00 UTC) > 46656000) ORDER BY `mobiles`.`price` ASC LIMIT 4' at line 1: SELECT `mobiles`.* FROM `mobiles` WHERE (price >= 123123.0 AND id != 11 AND visible = true) AND (ABS(release_date - 2016-04-10 00:00:00 UTC) > 46656000) ORDER BY `mobiles`.`price` ASC LIMIT 4

我想现在你可以得到我的逻辑了。实现它的正确语法是什么?

2 个答案:

答案 0 :(得分:4)

这里有几个提示:

  • 使用"#{}"运算符将变量连接到查询中是一种危险的做法。这样做可以绕过查询参数化,并可以将您的应用保持为SQL injection。相反,请在where子句中使用"?"
  • MySQL为您提供错误的原因是因为您将字符串连接到查询中而不将其封装在引号中。

考虑到这两件事,我首先要重构你的查询:

high = Mobile.where("price >= ?", @mobile.price)
         .where.not(id: @mobile.id)
         .where(visible: true)
         .where("ABS(release_date - ?) > 46656000", @mobile.release_date)
         .order(price: :ASC).first(4)

您会注意到我已将18.months替换为46656000。这样可以在Rails应用程序中节省几个时钟周期。根据您的数据库架构,最后一个where子句可能不起作用。以下修改可能会更好地运作。

作为进一步的改进,您可以重构最后一个where子句,以查找在@mobile.release_date到18个月之前的18个月之间的发布日期。保存您的MySql数据库不必对每条记录进行数学运算,并可能带来更好的性能:

.where(release_date: (@mobile.release_date - 18.months)..(@mobile.release_date + 18.months) )

我不知道您的数据库架构,因此您可能会遇到上述代码的日期转换问题。我建议你在Rails控制台中使用它。

答案 1 :(得分:0)

使用范围在日期/时间之间进行查询:

Mobile.where("price >= ?", @mobile.price)
      .where.not(id: @mobile.id)
      .where(release_date: 18.months.ago..Time.now)
      .order(price: :ASC)
      .first(4)