Я пытаюсь рассчитать расстояние между двумя позициями на карте. Я сохранил в своих данных: Долгота, Широта, 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
sql-server
tsql
math
sql-server-2008-r2
Уоллер
источник
источник
Ответы:
Поскольку вы используете 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 км от (около) Лондона до (около) Эдинбурга.
Естественно, сначала нужно будет поучиться, но как только вы это узнаете, это намного проще, чем реализовать собственное вычисление Хаверсина; плюс вы получаете МНОГО функциональных возможностей.
Если вы хотите сохранить существующую структуру данных, вы все равно можете использовать
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
Приведенная ниже функция дает расстояние между двумя географическими координатами в километрах с использованием типа данных 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)
Ссылка: Ref1 , Ref2
источник
Похоже, Microsoft вторглась в мозги всех остальных респондентов и заставила их написать максимально сложные решения. Вот самый простой способ без каких-либо дополнительных функций / заявлений:
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
источник
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 с помощью закомментированных поплавков.
источник
Поскольку вы используете SQL 2008 или новее, я бы рекомендовал проверить тип данных GEOGRAPHY . SQL имеет встроенную поддержку геопространственных запросов.
например, у вас будет столбец в вашей таблице типа GEOGRAPHY, который будет заполнен геопространственным представлением координат (см. ссылку MSDN, приведенную выше, для примеров). Затем этот тип данных предоставляет методы, позволяющие выполнять целый ряд геопространственных запросов (например, определение расстояния между двумя точками).
источник
В дополнение к предыдущим ответам, вот способ рассчитать расстояние внутри 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)
Скалярные функции также работают, но они очень неэффективны при вычислении больших объемов данных.
Надеюсь, это может кому-то помочь.
источник