简体   繁体   English

.where中两个日期之间的rails差异

[英]rails difference between two dates inside .where

Here is my logic I want to get the closest 4 more expensive mobiles to a specific mobile @mobile but under one condition the difference between the release dates of the two mobiles is not more than a year and half Here is the query 这是我的逻辑,我想将最昂贵的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)

The first .where() works perfectly but the second is not working and I get this error 第一个.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

I think now you can get my logic. 我想现在您可以理解我的逻辑了。 What is the right syntax to achieve it? 实现它的正确语法是什么?

A couple of tips here: 这里有几个提示:

  • It is a dangerous practice to concatenate variables into your queries using the "#{}" operator. 使用"#{}"运算符将变量连接到查询中是一种危险的做法。 Doing so bypasses query parameterization and could leave your app open to SQL injection . 这样做会绕过查询参数化,并可能使您的应用程序无法进行SQL注入 Instead, use "?" 而是使用"?" in your where clause. 在您的where子句中。
  • The reason MySQL is giving you an error is because you are concatenating a string into your query without encapsulating it in quotes. MySQL给您一个错误的原因是因为您正在将字符串连接到查询中,而没有将其封装在引号中。

With these two things in mind, I would start by refactoring your query like so: 考虑到这两点,我将以如下方式重构您的查询开始:

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)

You will note that I replaced 18.months with 46656000 . 您会注意到,我用18.months替换了46656000 This saves a few clock cycles in the Rails app. 这样可以在Rails应用程序中节省几个时钟周期。 Depending on your database schema, the last where clause may not work. 根据您的数据库架构,最后的where子句可能不起作用。 The modification below may end up working better. 下面的修改可能会更好地工作。

As a further refinement, you could refactor your last where clause to look for a release date that is between 18 months before @mobile.release_date and 18 months after. 作为进一步改进,您可以重构您的last where子句以查找发布日期,该发布日期在@mobile.release_date之前的18个月与之后的18个月之间。 The saves your MySql database from having to do the math on each record and may lead to better performance: 这样就不必对每条记录进行数学运算,从而节省了MySql数据库的时间,并且可能导致更好的性能:

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

I do not know your database schema, so you may run into date conversion problems with the code above. 我不知道您的数据库架构,因此您可能会遇到上述代码的日期转换问题。 I recommend you play with it in the Rails console. 我建议您在Rails控制台中使用它。

Use a Range to query between dates/times: 使用范围查询日期/时间之间:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM