2012-10-23 222 views
60

我正試圖計算地圖上兩個位置之間的距離。 我已經存儲在我的數據中:經度,緯度,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 

任何人可以幫助我與我的代碼,如果你想解決什麼我已經有了,如果你有實現的一種新的方式,我不介意這會很好。

請或註明您的結果是什麼計量單位。

+0

什麼數據庫系統? – AakashM

+0

MSSQL 2008 R2 .. – Waller

+0

您不應該通過附加/ 2將參數劃分爲正弦。另外,您可以在地球半徑中獲得更高的精度,並且可以使用一些_Datum_等。通過GPS系統(WGS-84),通過橢球體(在赤道和極點具有不同的半徑)逼近地球 –

回答

90

,您獲得了geography數據類型,它是專爲準確這樣的數據:

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

SELECT @source.STDistance(@target) 

給人

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

(1 row(s) affected) 

告訴我們它是538公里(近)倫敦(附近)愛丁堡。

自然會有大量的學習要做,但是一旦你知道它比實現自己的Haversine計算容易得多;再加上你獲得了很多功能。


如果你想保留現有的數據結構,你仍然可以使用STDistance,通過使用Point方法構造適當的geography實例:

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不 - 經度在[Prime Meridian](http://en.wikipedia.org/wiki/Prime_meridian)以西的地方爲負數,並且對它東邊的地方爲正 – AakashM

+0

你救了我的一天!非常感謝! –

3

當你使用SQL 2008後,我建議你檢查出GEOGRAPHY數據類型。 SQL已經構建了對地理空間查詢的支持。

例如您需要在您的GEOGRAPHY類型的表格中使用座標的地理空間表示(請參閱上面鏈接的MSDN參考資料中的示例)中的列。然後,這個數據類型公開的方法,允許您執行地理空間查詢一大堆由於您使用的SQL Server 2008(例如,尋找2點之間的距離)

+0

爲了增加,我嘗試了geography字段類型,但發現使用Durai的函數(直接使用經度和緯度值)要快得多。看到我的例子在這裏:http://stackoverflow.com/a/37326089/391605 –

31

下面的函數給出了兩個地理座標之間距離英里

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 

的以下函數中使用將其在引入Geography數據類型給出公里 地理座標距離之間的兩個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個地理座標之間的距離」失敗,如果我們比較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) 

標量函數也工作,但他們是非常低效的,當計算大量的數據。

我希望這可以幫助某人。

相關問題