2012-04-13 164 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