Sql server 给定两个lat/long,我如何判断它们之间的距离是否在1英里以内?

Sql server 给定两个lat/long,我如何判断它们之间的距离是否在1英里以内?,sql-server,performance,tsql,gis,haversine,Sql Server,Performance,Tsql,Gis,Haversine,我正在尝试实施一项非常有效的检查,以查看两个点之间是否在一英里以内 我只在乎他们是否在一英里之内,距离对我来说无关紧要 由于关注的范围很窄,我不是在寻找一个通用的“”函数 我目前的方法是计算距离,然后检查距离是否小于一英里 在这种情况下,效率很重要,因为我必须为大型记录集计算这个是/否标志 那么,判断两个横向/纵向点之间的距离是否在一英里以内的最有效方法是什么 我在T-SQL中做这个检查,这并不重要。 我目前的哈弗森计算如下 CREATE FUNCTION dbo.USR_UFN_HAVERSI

我正在尝试实施一项非常有效的检查,以查看两个点之间是否在一英里以内

我只在乎他们是否在一英里之内,距离对我来说无关紧要

由于关注的范围很窄,我不是在寻找一个通用的“”函数

我目前的方法是计算距离,然后检查距离是否小于一英里

在这种情况下,效率很重要,因为我必须为大型记录集计算这个是/否标志

那么,判断两个横向/纵向点之间的距离是否在一英里以内的最有效方法是什么

我在T-SQL中做这个检查,这并不重要。 我目前的哈弗森计算如下

CREATE FUNCTION dbo.USR_UFN_HAVERSINE_DISTANCE
(
  @LAT1 FLOAT(18)
 ,@LONG1 FLOAT(18)
 ,@LAT2 FLOAT(18)
 ,@LONG2 FLOAT(18)
 ,@UnitOfMeasure NVARCHAR(10) = 'KILOMETERS'
)
RETURNS FLOAT(18)
AS
BEGIN
  DECLARE
    @R FLOAT(8)
   ,@DLAT FLOAT(18)
   ,@DLON FLOAT(18)
   ,@A FLOAT(18)
   ,@C FLOAT(18)
   ,@D FLOAT(18)
   ;
  SET @R =
    CASE @UnitOfMeasure
      WHEN 'MILES'      THEN 3956.55 
      WHEN 'KILOMETERS' THEN 6367.45
      WHEN 'FEET'       THEN 20890584
      WHEN 'METERS'     THEN 6367450
      ELSE 6367.45  --km
    END
  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;
-返回值以米为单位,但您可以通过更改SRID来指定返回值

-此处提供了SRID的列表

 Select * from sys.spatial_reference_systems
-返回值以米为单位,但您可以通过更改SRID来指定返回值

-此处提供了SRID的列表

 Select * from sys.spatial_reference_systems

由于您指定需要在大型数据集上运行此函数,因此我建议使用表值函数。如果您可以预先计算地理点,效果会更好,但这会以内联方式完成

create function dbo.fn_areWithinOneMile(@long1 float, @lat1 float, @long2 float, @lat2 float)
returns table
as
return

    select cast(
        case when 
            geography::Point(@lat1, @long1, 4236).STDistance(geography::Point(@lat2, @long2, 4236)) > 1609.34 then 0 
            else 1 
        end as bit) as [withinOneMile?]

go

with cte as (select * from (values
    (42, 42),
    (43, 43),
    (44, 44)
    ) as x(lat, long)
), j as (
    select long, lat, lag(long, 1) over (order by lat) as long2, lag(lat, 1) over (order by lat) as lat2
    from cte
)
select *
from j
cross apply dbo.fn_areWithinOneMile(long, lat, long2, lat2) as o
where long2 is not null;

由于您指定需要在大型数据集上运行此函数,因此我建议使用表值函数。如果您可以预先计算地理点,效果会更好,但这会以内联方式完成

create function dbo.fn_areWithinOneMile(@long1 float, @lat1 float, @long2 float, @lat2 float)
returns table
as
return

    select cast(
        case when 
            geography::Point(@lat1, @long1, 4236).STDistance(geography::Point(@lat2, @long2, 4236)) > 1609.34 then 0 
            else 1 
        end as bit) as [withinOneMile?]

go

with cte as (select * from (values
    (42, 42),
    (43, 43),
    (44, 44)
    ) as x(lat, long)
), j as (
    select long, lat, lag(long, 1) over (order by lat) as long2, lag(lat, 1) over (order by lat) as lat2
    from cte
)
select *
from j
cross apply dbo.fn_areWithinOneMile(long, lat, long2, lat2) as o
where long2 is not null;

可能是@KenY-N的副本谢谢你指点我。我已经有了一个通用函数来计算两点之间的距离。因为在这种情况下,我只关心距离是否在一英里之内,我希望有一种更快的方法,而不必实际计算整个距离。我对问题进行了编辑,试图澄清这一区别。请检查链接问题的第二个答案?似乎正朝着你想要的方向发展…游戏将要做的是在运行实际计算之前首先检查x<1英里和y<1英里。基本上,我们很早就开始计算。1°纬度约为69英里,因此如果
Abs(@Lat1-@Lat2)>1.0/69.0
,则距离至少为1英里。经度的1°随纬度的不同而变化,例如,在45°纬度处约50英里。根据您的数据,它可能值得检查,例如,
Abs(@Lat1)可能与@KenY-N重复感谢您给我指了指。我已经有了一个通用函数来计算两点之间的距离。因为在这种情况下,我只关心距离是否在一英里之内,我希望有一种更快的方法,而不必实际计算整个距离。我对问题进行了编辑,试图澄清这一区别。请检查链接问题的第二个答案?似乎正朝着你想要的方向发展…游戏将要做的是在运行实际计算之前首先检查x<1英里和y<1英里。基本上,我们很早就开始计算。1°纬度约为69英里,因此如果
Abs(@Lat1-@Lat2)>1.0/69.0
,则距离至少为1英里。经度的1°随纬度的不同而变化,例如,在45°纬度处约50英里。根据您的数据,它可能值得检查,例如
Abs(@Lat1)