21

私は保持し、Position(lat,lon)保持するデータベースモデルを持っていますlatitudeslongitudes.

show_close_by度単位の位置(my_lat, my_lon)、許容範囲(キロメートル単位)を受け取り、許容範囲内にあるデータベース内の位置のリストを返すコントローラーアクションがあります。

そのために、2つの座標間の距離(地球の表面上)をキロメートルで計算する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)ネストされたクエリを作成しますか?そうでない場合、どのように?

どうもありがとう!

4

2 に答える 2

34

ネストされたクエリを作成する方法は次のとおりです。

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)

sのみ がテーブルidからフェッチされることに注意してください。products2つのエンティティを接続する別の方法を作成しようとしていて、この魔法が適切でない場合は、を使用してProduct.select(:some_field).where(...)ください。

于 2012-04-13T20:39:53.737 に答える
1

更新された回答を提案したいと思います。Rails v5.0.xではselect、ネストされたクエリを実行しながら、id以外の属性を使用するために使用できます。

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