2012-01-20 12 views
4

は以下の表を考える:与えられたLatitudeに参加距離ベース/経度

table A (id, latitude, longitude) 
table B (id, latitude, longitude) 

どのように私はB内の最も近い行で各行を関連づける効率的なT-SQLクエリを構築するのですか?

ResultSetが私が探しているフォーマットは以下の通りですA内のすべての行が含まれており、Bで1と1つだけの要素とそれらを関連付ける必要があります。

(A.id, B.id, distanceAB) 

私が計算する関数を持っています緯度と経度の2つのペアが与えられた距離。私はorder by ... limit 1および/またはrank() over (partition by ...) as rowCount ... where rowCount = 1を使って何かを試しましたが、結果は本当に必要なものではないか、返すのに時間がかかりすぎます。

何か不足していますか?

答えて

1

約20単位半径内の任意のB行を探しているあなたは基本的に行っている。これは、deceentた性能を持っていなければならない一つのアプローチですが、大きな注意点は、それがどんな結果

select top 1 a.id,b.id,dbo.yourFunction() as DistanceAB 
    from a 
    join b on b.latitude between a.latitude-10 and a.latitude+10 and 
       b.longititude between a.longitude-10 and b.longittude+10 
    order by 3 

を見つけられないかもしれないということです最も近いものを決定するためにあなたの関数でそれをソートします。必要に応じて単位半径を調整することができます。それは正確ではありませんが、結果セットのサイズが小さくなり、適切なパフォーマンス結果が得られるはずです。

0

2つのサブクエリの結合で可能です。 1つ目はAとBの間の距離を含み、2つ目はAの位置からのBの距離の最小距離のみを含みます。

SELECT x.aid, x.bid, x.distance 
FROM 
(SELECT A.ID AS aid, 
     B.ID AS bid, 
     SQRT(A.Latitude * A.Latitude + B.Longitude * B.Longitude) AS Distance 
    FROM LocationsA AS A 
    CROSS JOIN LocationsB AS B) x JOIN 
(SELECT A.ID AS aid, 
     MIN(SQRT(A.Latitude * A.Latitude + B.Longitude * B.Longitude)) AS Distance 
    FROM LocationsA AS A 
    CROSS JOIN LocationsB AS B 
    GROUP BY A.ID) y ON x.aid = y.aid AND x.Distance = y.Distance 
5

あなたはAとBの両方が、多くのが含まれている場合、明らかに不十分な拡張しようとしているBのすべてのレコード、とにすべてのレコードを比較する必要があるとしているという事実を回避する方法はありません記録。言われていること

、これは正しい結果を返します:あなたのセットが大きすぎていない場合

SELECT aid, bid, distanceAB 
FROM (
    SELECT aid, bid, distanceAB, 
    dense_rank() over (partition by aid order by distanceAB) as n 
    FROM (
    SELECT a.id as aid, B.id as bid, 
     acos(sin(radians(A.lat)) * sin(radians(B.lat)) + 
     cos(radians(A.lat)) * cos(radians(B.lat)) * 
     cos(radians(A.lon - B.lon))) * 6372.8 as distanceAB 
    FROM A cross join B 
) C 
) D 
WHERE n = 1 

は、これは妥当な時間内に戻ります。 Aの3つの場所とBの130,000ほどの場所で、私のマシンでは約1秒かかります。それぞれに1,000レコードが約40秒かかる。私が言ったように、それは貧弱なスケールです。

Sparkyの回答は、特定の状況では誤った結果を返す可能性があることに注意してください。あなたのAの場所が+ 40、+ 100であるとします。 + 40、+ 111は、+ 49、+ 109よりも近くても返されません。

関連する問題