Расчет расстояния между двумя точками (широта, долгота)
Я пытаюсь вычислить расстояние между двумя позициями на карте. Я сохранил в своих данных: долгота, широта, 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
может кто-нибудь помочь мне с моим код, я не возражаю, если вы хотите исправить то, что я уже есть, если у вас есть новый способ достижения этого, что было бы здорово.
пожалуйста, укажите, в какой единице измерения находятся ваши результаты.
6 ответов:
так как вы используете 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)
говорит нам, что это около 538 км от (рядом) Лондона до (рядом) Эдинбурга.
естественно, сначала будет много учиться, но как только вы это узнаете, это намного проще, чем реализовать свой собственный расчет 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
ниже функция дает расстояние между двумя географические координаты в милях
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
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
Как вы используете SQL 2008 или более поздней версии, я бы рекомендовал проверить география тип данных. 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 с помощью комментируемых поплавков.
в дополнение к предыдущим ответам, вот способ рассчитать расстояние внутри выбора:
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)
Я надеюсь, что это может помочь кому-то.
похоже, что Microsoft вторглась в мозги всех других респондентов и заставила их писать как можно более сложные решения. Вот это самый простой способ без каких-либо дополнительных функций/операторов declare:
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