두 지점 사이의 거리 계산 (위도, 경도)


88

지도에서 두 위치 사이의 거리를 계산하려고합니다. 경도, 위도, 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

아무도 내 코드로 나를 도울 수 있습니까?이를 달성하는 새로운 방법이 있다면 이미 가지고있는 것을 고치고 싶다면 괜찮습니다.

결과의 측정 단위를 명시하십시오.


사인 인수를 추가 / 2로 나누면 안됩니다. 또한 지구 반경에서 더 많은 정확도를 가질 수있을뿐만 아니라 GPS 시스템 (WGS-84)에서 사용되는 일부 데이텀을 사용할 수 있습니다. 예를 들어 타원체 (적도 및 극에서 다른 반경)로 지구를 근사화 하는 데이텀을 사용할 수 있습니다.
Aki Suihkonen

@Waller, 왜 이것을 달성하기 위해 지리 / 기하학 (공간) 유형을 사용하지 않습니까?
Habib

3
Mathematica로 계산을 확인했습니다. 법정 마일 (5280 피트) 단위의 거리가 42.997이라고 생각합니다. 이는 계산이 약간 부정확 한 것이 아니라 매우 부정확하다는 것을 의미 합니다.
High Performance Mark

답변:


128

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

6
@nezam no-경도는 본초 자오선 서쪽 장소에 대해 음수 이고 동쪽 장소에 대해 양수입니다
AakashM

당신은 내 하루를 구했습니다! .. 정말 감사합니다!
Dhrumil Bhankhar 2015

1
내장 기능을 사용하는 것은 매우 느린 것 같습니다. 예를 들어 100,000 항목 루프에서 사용자 정의 함수에 1.4 초 대신 23 초가 걸립니다 (Durai의 답변 참조).
NickG

1
그냥 공간 인덱스를 구현 한 후에 더 좋은 크기의 몇 배를에 차임을 원하고 ETL 응용 프로그램을위한 공간 인덱스 + ...에 대한 확인 @AakashM의 추천, 차이가 있었다
빌 안톤

3
참고 : POINT (LONGITUDE LATITUDE) 반면 geography :: Point (LATITUDE, LONGITUDE, 4326)
Mzn

41

아래 함수는 두 지리 좌표 사이의 거리를 마일 단위로 제공합니다.

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 

아래 함수는 두 지리 좌표 사이의 거리를 킬로미터 단위로 제공합니다.

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

아래 함수는 SQL Server 2008에 도입 된 Geography 데이터 형식을 사용하여 지리 좌표 사이의 거리를 킬로미터 단위로 제공 합니다.

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)

참조 : Ref1 , Ref2


2
우편 번호까지의 거리를 기준으로 정렬 된 다양한 이벤트의 우편 번호에 대해 35K 우편 번호에 대한 거리 계산을 수행해야했습니다. 지리 데이터 유형을 사용하여 계산을 수행하기에는 좌표 목록이 너무 큽니다. 위의 단일 라인 삼각 함수 기반 솔루션을 사용하도록 전환했을 때 훨씬 빠르게 실행되었습니다. 따라서 거리를 계산하기 위해 지리 유형을 사용하는 것은 비용이 많이 드는 것 같습니다. 구매자는 조심하십시오.
Tombala

쿼리의 WHERE 절에서 거리를 계산하는 데 매우 유용합니다. 함수가 음의 거리를 반환하는 경우를 발견했기 때문에 "set @ d ="표현식 주위에 ABS ()를 래핑해야했습니다.
조 Irby

1
두 개의 동일한 점을 비교하면 "두 지 좌표 사이의 거리 (km)"기능이 실패하고 "잘못된 부동 소수점 연산이 발생했습니다"라는 오류가 발생합니다.
RRM

2
이것은 훌륭했지만 "decimal (8,4)"가 충분한 정밀도를 제공하지 않기 때문에 짧은 거리에서는 작동하지 않습니다.
유입수

1
@influent는 정확합니다. 단거리에서는 유용하지 않습니다 (제 경우에는 5 마일)
Roger

15

마이크로 소프트가 다른 모든 응답자의 두뇌를 침범하여 가능한 한 복잡한 솔루션을 작성하게 한 것 같습니다. 다음은 추가 함수 / 선언문없이 가장 간단한 방법입니다.

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

2
참고로 : STDistance ()는 지리 데이터가 정의 된 공간 참조 시스템의 선형 측정 단위로 거리를 반환합니다. SRID 4326을 사용하고 있는데 이는 STDistance ()가 거리를 미터 단위로 반환 함을 의미합니다.
Bryan Stump

4

SQL 2008 이상을 사용하고 있으므로 GEOGRAPHY 데이터 유형을 확인하는 것이 좋습니다 . SQL에는 지리 공간 쿼리에 대한 지원이 내장되어 있습니다.

예를 들어, 좌표의 지리 공간 표현으로 채워지는 GEOGRAPHY 유형의 테이블에 열이있을 것입니다 (예를 보려면 위에 링크 된 MSDN 참조를 확인하십시오). 그런 다음이 데이터 유형은 전체 호스트의 지리 공간 쿼리를 수행 할 수있는 메서드를 노출합니다 (예 : 두 지점 사이의 거리 찾기).


추가하기 위해 지리 필드 유형을 시도했지만 Durai의 기능 (경도와 위도 값을 직접 사용)을 사용하는 것이 훨씬 빠르다 는 것을 알았습니다 . 여기 내 예를 참조하십시오 stackoverflow.com/a/37326089/391605
마이크 Gledhill

4
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 매개 변수를 변경할 수 있습니다.


완벽하게 작동합니다
Tejasvi Hegde 2018-08-27

1

이전 답변 외에도 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)

스칼라 함수도 작동하지만 많은 양의 데이터를 계산할 때 매우 비효율적입니다.

나는 이것이 누군가를 도울 수 있기를 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.