Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails Nested SQL Queries

Tags:

I have a database model Position(lat,lon) which holds latitudes and longitudes.

I have a controller action called show_close_by which recieves a position in degrees (my_lat, my_lon), a tolerance (in kilometers) and should return the list of positions in the database that are within tolerance range.

For that, I use the haversine_distance formula which calculates the distance in kilometers (on the surface of the Earth) between two coordinates (lat1, lon1, lat2, lon2).

To make the query faster, I wrote the whole haversine_distance formula in the query:

... WHERE 2*6371*asin(sqrt( power( sin( (:lat2-latitude)*pi()/(180*2) ) ,2) + cos(latitude*pi()/180)*cos(:lat2*pi()/180)*power(sin( (:lon2-longitude)*pi()/(180*2) ),2) )) < tolerance 

The specifics of the query don't matter. My doubt is: is it necessary to calculate this huge function for EVERY position in the database? Can I filter out some positions that are clearly too far away with a simpler function?

Well, I can: With a nested SQL query, I can query the database for positions that are within a large "square" (in lat/lon space), and then filter those with the more costly trigonometric function. Something like the following:

SELECT * FROM ( SELECT * FROM Positions WHERE lat-latitude < some_reasonable_upper_bound AND lon-longitude < same_upper_bound ) WHERE costly_haversine_distance < tolerance 

Finally, my question: how can I implement this in Rails (without writing the whole query myself)? Does Positions.where(reasonable_upper_bound).where(costly_but_accurate_restriction) make a nested query? If not, how?

Thanks a lot!

like image 445
gdiazc Avatar asked Apr 13 '12 19:04

gdiazc


People also ask

What is Arel_table?

The Arel::Table object acts like a hash which contains each column on the table. The columns given by Arel are a type of Node , which means it has several methods available on it to construct queries. You can find a list of most of the methods available on Node s in the file predications.

What is eager loading rails?

Eager loading lets you preload the associated data (authors) for all the posts from the database, improves the overall performance by reducing the number of queries, and provides you with the data that you want to display in your views, but the only catch here is which one to use. Gotcha!

What are active records in Rails?

Rails Active Records provide an interface and binding between the tables in a relational database and the Ruby program code that manipulates database records. Ruby method names are automatically generated from the field names of database tables.


1 Answers

Here's how to make nested queries:

LineItem.where(product_id: Product.where(price: 50)) 

It makes the following request:

SELECT "line_items".* FROM "line_items"  WHERE "line_items"."product_id" IN  (SELECT "products"."id" FROM "products" WHERE "products"."price" = 50) 

Note that only ids will be fetched from the products table. If you are trying to make another way to connect two entities and this magic isn't suitable, use Product.select(:some_field).where(...).

like image 87
jdoe Avatar answered Oct 26 '22 19:10

jdoe