21

我有一个数据库模型Position(lat,lon),它拥有latitudes并且longitudes.

我有一个名为的控制器操作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)进行嵌套查询?如果没有,怎么办?

非常感谢!

4

2 回答 2

34

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

于 2012-04-13T20:39:53.737 回答
1

我想建议一个更新的答案。在 Rails v5.0.x 中,您可以使用selectid 以外的属性,同时仍然执行嵌套查询。

LineItem.where(product_id: Order.where(price: 50).select(:product_id))
于 2019-07-16T03:21:41.500 回答