地図上の2つの位置間の距離を計算しようとしています。経度、緯度、X POS、Y POSのデータを保存しました。
以前は以下のスニペットを使用していました。
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 Server 2008を使用しているため、 geography
データ型を使用できます。これは、まさにこの種類のデータ用に設計されています。
DECLARE @source geography = 'POINT(0 51.5)'
DECLARE @target geography = 'POINT(-3 56)'
SELECT @source.STDistance(@target)
与える
----------------------
538404.100197555
(1 row(s) affected)
ロンドンから(近く)エディンバラまで約538kmです。
当然のことながら、最初にやることはたくさんありますが、一度知ってしまえば、独自のHaversine計算を実装するよりもはるかに簡単です。さらに、多くの機能を利用できます。
既存のデータ構造を保持したい場合は、 STDistance
メソッドを使用して適切なgeography
インスタンスを構築することにより、Point
を引き続き使用できます。
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
以下の関数は、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
以下の関数は、キロメートル単位の2つの地理座標間の距離
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)
マイクロソフトは、他のすべての回答者の頭脳に侵入し、できるだけ複雑なソリューションを作成させたようです。追加の関数/宣言ステートメントを使用しない最も簡単な方法を次に示します。
SELECT geography::Point(LATITUDE_1, LONGITUDE_1, 4326).STDistance(geography::Point(LATITUDE_2, LONGITUDE_2, 4326))
LATITUDE_1
、LONGITUDE_1
、LATITUDE_2
、LONGITUDE_2
の代わりに、単にデータを置き換えてください。例:
SELECT geography::Point(53.429108, -2.500953, 4326).STDistance(geography::Point(c.Latitude, c.Longitude, 4326))
from coordinates c
SQL 2008以降を使用しているので、 GEOGRAPHY データ型をチェックアウトすることをお勧めします。 SQLには、地理空間クエリのサポートが組み込まれています。
例えばテーブルにGEOGRAPHYタイプの列があり、そこに座標の地理空間表現が入力されます(上記のリンク先のMSDNリファレンスを参照してください)。次に、このデータ型は、地理空間クエリのホスト全体を実行できるメソッドを公開します(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パラメータを変更できます。
前の回答に加えて、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)
スカラー関数も機能しますが、大量のデータを計算する場合は非常に非効率的です。
これが誰かの助けになることを願っています。