Home rails difference between two dates inside .where
Reply: 2

rails difference between two dates inside .where

amronrails
1#
amronrails Published in 2017-11-06 23:24:12Z

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

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

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?

Tom Aranda
2#
Tom Aranda Reply to 2017-11-07 06:28:43Z

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. Instead, use "?" in your where clause.
  • The reason MySQL is giving you an error is because you are concatenating a string into your query without encapsulating it in quotes.

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. This saves a few clock cycles in the Rails app. Depending on your database schema, the last where clause may not work. 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. The saves your MySql database from having to do the math on each record and may lead to better performance:

.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.

max
3#
max Reply to 2017-11-07 00:16:02Z

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)
You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.318668 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO