2012-04-13 136 views
15

我有一个数据库模型Position(lat,lon)持有latitudeslongitudes.Rails的嵌套SQL查询

我有一个名为show_close_by控制器动作,其临危度(my_lat, my_lon)的位置公差(千米),并应返回职位列表在容差范围内的数据库中。

为此,我使用haversine_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)是否进行嵌套查询?如果没有,如何?

非常感谢!

+0

你知道[Geocoder](https://github.com/alexreisner/geocoder)吗?你可以安装gem,在你的Position模型中添加一行,然后你可以做'Position.near([40.71,100.23],20)''。这个宝石很受欢迎,所以我会说他们做你想做得很好的事情。 (所以你知道,连接'where'子句不会做你想做的事情,我认为它只是覆盖了以前的)。 – Robin 2012-04-13 19:47:48

+0

是的,我知道地理编码器,我可能会最终使用它,但它似乎有点大,我想(我只是想要物体之间的距离)。加载整个Geocoder对象的应用程序相比于我编程的准系统hasrsine_distance函数要慢多少? – gdiazc 2012-04-13 20:01:20

+0

@Robin它不覆盖前面的那个,但它会*使用'AND'将当前查询的条件追加到当前查询中,这并不是寻找者正在寻找的东西。 – nzifnab 2012-04-13 20:57:10

回答

25

下面是如何使嵌套查询:

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

+0

感谢您的帖子,但我需要一点不同的帮助..如何编写查询,如果我需要选择所有消息之间通信两个用户(说id1&id2)和消息有sender_id和receiver_id。所以我需要选择“((sender_id = id1和reciver_id = id2)或(sender_id = id2和reciver_id = id1))”的所有邮件。我需要对它们进行排序和分页,如果我做两个单独的查询然后添加它们(我将得到期望的结果,但分页变得困难),这是无法完成的。所以请帮我写单行查询。任何帮助将不胜感激。 – zeal 2014-08-06 20:26:55

+0

@zeal尝试https:// github。com/activerecord-hackery/squeel用于复杂的查询。 – jdoe 2014-08-07 17:48:34