Rails嵌套SQL查询

时间:2012-04-13 19:41:39

标签: sql ruby-on-rails

我有一个数据库模型Position(lat,lon),其中包含latitudeslongitudes.

我有一个名为show_close_by的控制器动作,它接收一个度(my_lat, my_lon)的位置,一个公差(以公里为单位),并且应该返回数据库中位于公差范围内的位置列表。

为此,我使用hasrsine_distance公式计算两个坐标(lat1, lon1, lat2, lon2)之间的公里距离(在地球表面上)。

为了加快查询速度,我在查询中编写了整个haversine_distance公式:

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

查询的细节无关紧要。我的疑问是:是否有必要为数据库中的每个位置计算这个巨大的函数?我可以使用更简单的功能过滤掉一些显然太远的位置吗?

嗯,我可以:使用嵌套的SQL查询,我可以在数据库中查询大“正方形”(在纬度/经度空间内)的位置,然后使用更昂贵的三角函数过滤那些位置。如下所示:

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

最后,我的问题是:如何在Rails中实现这一点(不自己编写整个查询)? Positions.where(reasonable_upper_bound).where(costly_but_accurate_restriction)是否进行嵌套查询?如果没有,怎么样?

非常感谢!

2 个答案:

答案 0 :(得分:26)

以下是如何进行嵌套查询:

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

它提出以下要求:

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

请注意, id将从products表中提取。如果您尝试使用另一种方式连接两个实体并且此魔法不合适,请使用Product.select(:some_field).where(...)

答案 1 :(得分:0)

我想提出一个更新的答案。在Rails v5.0.x中,可以在进行嵌套查询的同时使用select使用id以外的属性。

LineItem.where(product_id: Order.where(price: 50).select(:product_id))