2012-10-23 25 views
60

マップ上の2つの位置の間の距離を計算しようとしています。 私は自分のデータに保管しています:経度、緯度、X POS、Y POS。2点間の距離の計算(緯度、経度)

私はこれまで、以下のスニペットを使用しています。

DECLARE @orig_lat DECIMAL 
DECLARE @orig_lng DECIMAL 
SET @orig_lat=53.381538 set @orig_lng=-1.463526 
SELECT *, 
    3956 * 2 * ASIN(
      SQRT(POWER(SIN((@orig_lat - abs(dest.Latitude)) * pi()/180/2), 2) 
       + COS(@orig_lng * pi()/180) * COS(abs(dest.Latitude) * pi()/180) 
       * POWER(SIN((@orig_lng - dest.Longitude) * pi()/180/2), 2))) 
      AS distance 
--INTO #includeDistances 
FROM #orig dest 

私はこのデータが信頼できないものの、やや不正確な結果を示しているようです。

あなたが達成するための新しい方法を持っている場合、私は既に持っているものを修正したい場合は、それを

Latitude  Longitude  Distance 
53.429108  -2.500953  85.2981833133896 

が必要な場合はいくつかのサンプルデータは、誰もが私のコードで私を助けることができる、私は気にしませんこれは素晴らしいだろう。あなたは、SQL 2008以降を使用しているとして

あなたの結果がでている測定の何単位明記してください。

+0

どのデータベースシステムですか? – AakashM

+0

MSSQL 2008 R2 .. – Waller

+0

追加の/ 2で引数をsineに分割しないでください。また、地球半径の精度を高めることもできますし、例えば_Datum_を使用することもできます。地球を楕円体(赤道と極に異なる半径を持つ)で近似するGPSシステム(WGS-84) –

答えて

90

SQL Server 2008を使用しているため、正確に設計されたgeographyデータ型この種のデータ:

DECLARE @source geography = 'POINT(0 51.5)' 
DECLARE @target geography = 'POINT(-3 56)' 

SELECT @source.STDistance(@target) 

は、それが(近く)エディンバラ(近い)ロンドンからおよそ538キロである私たちに言って

---------------------- 
538404.100197555 

(1 row(s) affected) 

を与えます。

当然のことながら、まず最初に行うべき学習の量がありますが、それを知ったら、自分のHaversine計算を実装するよりはるかに簡単です。さらに多くの機能を利用できます。


既存のデータ構造を保持したい場合、あなたはまだPoint方法を用いて適切なgeographyインスタンスを構築することにより、STDistanceを使用することができます。

DECLARE @orig_lat DECIMAL(12, 9) 
DECLARE @orig_lng DECIMAL(12, 9) 
SET @orig_lat=53.381538 set @orig_lng=-1.463526 

DECLARE @orig geography = geography::Point(@orig_lat, @orig_lng, 4326); 

SELECT *, 
    @orig.STDistance(geography::Point(dest.Latitude, dest.Longitude, 4326)) 
     AS distance 
--INTO #includeDistances 
FROM #orig dest 
+1

経度が負であることは必須ですか? – Nezam

+5

@nezam no - 経度は[Prime Meridian](http://en.wikipedia.org/wiki/Prime_meridian)の西側の場所では負であり、東側の場所では正の値になります – AakashM

+0

あなたは私の日を救ってくれました!どうもありがとう! –

3

を、私はGEOGRAPHYデータ型をチェックアウトをお勧めしたいです。 SQLでは、地理空間クエリのサポートが組み込まれています。

GEOGRAPHY型のテーブルに座標の地理空間表示が設定された列があります(上記のリンク先の例を参照してください)。このデータ型では、(例えば2点間の距離を求めるなど)完全な地理空間クエリを実行できるメソッドが公開されます。

+0

ちょうど追加するには、地理フィールドのタイプを試しましたが、Duraiの関数(経度と緯度の値を直接使用して)を使って*はるかに*高速です。ここの私の例を見てください:http://stackoverflow.com/a/37326089/391605 –

31

以下の関数は、2つの地理座標間の距離を与えるにはマイル単位で

create function [dbo].[fnCalcDistanceMiles] (@Lat1 decimal(8,4), @Long1 decimal(8,4), @Lat2 decimal(8,4), @Long2 decimal(8,4)) 
returns decimal (8,4) as 
begin 
declare @d decimal(28,10) 
-- Convert to radians 
set @Lat1 = @Lat1/57.2958 
set @Long1 = @Long1/57.2958 
set @Lat2 = @Lat2/57.2958 
set @Long2 = @Long2/57.2958 
-- Calc distance 
set @d = (Sin(@Lat1) * Sin(@Lat2)) + (Cos(@Lat1) * Cos(@Lat2) * Cos(@Long2 - @Long1)) 
-- Convert to miles 
if @d <> 0 
begin 
set @d = 3958.75 * Atan(Sqrt(1 - power(@d, 2))/@d); 
end 
return @d 
end 

は、以下の関数は、以下の機能が導入されましたGeographyデータ型を使用してキロ で距離両者の地理座標を与える

CREATE FUNCTION dbo.fnCalcDistanceKM(@lat1 FLOAT, @lat2 FLOAT, @lon1 FLOAT, @lon2 FLOAT) 
RETURNS FLOAT 
AS 
BEGIN 

    RETURN ACOS(SIN(PI()*@lat1/180.0)*SIN(PI()*@lat2/180.0)+COS(PI()*@lat1/180.0)*COS(PI()*@lat2/180.0)*COS(PI()*@lon2/180.0-PI()*@lon1/180.0))*6371 
END 

キロ内の2株の地理座標間距離を与えますSQL Server 2008

DECLARE @g geography; 
DECLARE @h geography; 
SET @g = geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656)', 4326); 
SET @h = geography::STGeomFromText('POINT(-122.34900 47.65100)', 4326); 
SELECT @g.STDistance(@h); 

用途:

select [dbo].[fnCalcDistanceKM](13.077085,80.262675,13.065701,80.258916) 

リファレンス:Ref1Ref2

+1

郵便番号までの距離で並べられたさまざまなイベントの郵便番号に対する35K郵便番号の距離計算が必要でした。地理データ型を使用して計算を行うには、座標のリストが大きすぎます。上記のシングルラインtrig関数ベースのソリューションを使用するように切り替えると、はるかに高速に実行されました。したがって、地理タイプを使用して距離を計算するだけでは、費用がかかるようです。バイヤーは注意してください。 – Tombala

+0

クエリのWHERE句で距離を計算するのに非常に便利です。私は、関数が負の距離を返したいくつかのケースを見つけたので、 "set @ d ="式の周りにABS()をラップする必要がありました。 –

+0

"2つの地理座標間の距離(km)"の機能は、2等分点を比較するとエラーになります。 "無効な浮動小数点演算が発生しました" – RRM

2
Create Function [dbo].[DistanceKM] 
( 
     @Lat1 Float(18), 
     @Lat2 Float(18), 
     @Long1 Float(18), 
     @Long2 Float(18) 
) 
Returns Float(18) 
AS 
Begin 
     Declare @R Float(8); 
     Declare @dLat Float(18); 
     Declare @dLon Float(18); 
     Declare @a Float(18); 
     Declare @c Float(18); 
     Declare @d Float(18); 
     Set @R = 6367.45 
      --Miles 3956.55 
      --Kilometers 6367.45 
      --Feet 20890584 
      --Meters 6367450 


     Set @dLat = Radians(@lat2 - @lat1); 
     Set @dLon = Radians(@long2 - @long1); 
     Set @a = Sin(@dLat/2) 
       * Sin(@dLat/2) 
       + Cos(Radians(@lat1)) 
       * Cos(Radians(@lat2)) 
       * Sin(@dLon/2) 
       * Sin(@dLon/2); 
     Set @c = 2 * Asin(Min(Sqrt(@a))); 

     Set @d = @R * @c; 
     Return @d; 

End 
GO 

用途:

dbo.DistanceKM(37.848832506474、37.848732506474、27.83935546875、27.83905546875)を選択

出力:

0,02849639

あなたがコメントしたフロートと@Rパラメータを変更することができます。前回の回答に加えて

0

は、ここにSELECT内の距離を計算する方法です:

CREATE FUNCTION Get_Distance 
( 
    @La1 float , @Lo1 float , @La2 float, @Lo2 float 
) 
RETURNS TABLE 
AS 
RETURN 
    -- Distance in Meters 
    SELECT GEOGRAPHY::Point(@La1, @Lo1, 4326).STDistance(GEOGRAPHY::Point(@La2, @Lo2, 4326)) 
    AS Distance 
GO 

使用法:

select Distance 
from Place P1, 
    Place P2, 
outer apply dbo.Get_Distance(P1.latitude, P1.longitude, P2.latitude, P2.longitude) 

スカラー関数も動作しますが、彼らはときに非常に非効率的です大量のデータを計算します。

私はこれが誰かを助けてくれることを願っています。