Sql 给定纬度/经度的基于距离的联接

Sql 给定纬度/经度的基于距离的联接,sql,tsql,join,distance,haversine,Sql,Tsql,Join,Distance,Haversine,鉴于下表: table A (id, latitude, longitude) table B (id, latitude, longitude) 如何构建一个高效的T-SQL查询,将A中的每一行与B中最近的行关联起来 ResultSet应该包含A中的所有行,并将它们与B中的1个元素关联,并且仅与B中的1个元素关联。我要查找的格式如下: (A.id, B.id, distanceAB) 我有一个函数,计算给定2对经纬度的距离。我尝试了一些使用orderby。。。将1和/或rank()限制为行

鉴于下表:

table A (id, latitude, longitude)
table B (id, latitude, longitude)
如何构建一个高效的T-SQL查询,将A中的每一行与B中最近的行关联起来

ResultSet应该包含A中的所有行,并将它们与B中的1个元素关联,并且仅与B中的1个元素关联。我要查找的格式如下:

(A.id, B.id, distanceAB)
我有一个函数,计算给定2对经纬度的距离。我尝试了一些使用
orderby。。。将1
和/或
rank()限制为行计数(分区依据…)。。。其中rowCount=1
,但结果要么不是我真正需要的结果,要么返回的时间太长


我错过什么了吗

这是一种应该具有良好性能的方法,但一个大的警告是,它可能找不到任何结果

    select top 1 a.id,b.id,dbo.yourFunction() as DistanceAB
    from a 
    join b on b.latitude between a.latitude-10 and a.latitude+10 and
              b.longititude between a.longitude-10 and b.longittude+10
    order by 3

基本上,您要做的是查找a半径大约为20个单位内的任何B行,然后根据函数对其进行排序,以确定最接近的B行。您可以根据需要调整单位半径。虽然这并不精确,但它应该减少结果集的大小,并提供良好的性能结果。

两个子查询的联接是可能的。第一个包含A和B位置之间的所有距离,第二个仅包含B位置与A位置之间的最小距离

SELECT x.aid, x.bid, x.distance
FROM
(SELECT A.ID AS aid, 
        B.ID AS bid, 
        SQRT(A.Latitude * A.Latitude + B.Longitude * B.Longitude) AS Distance
     FROM LocationsA AS A 
     CROSS JOIN LocationsB AS B) x JOIN
(SELECT A.ID AS aid, 
        MIN(SQRT(A.Latitude * A.Latitude + B.Longitude * B.Longitude)) AS Distance
     FROM LocationsA AS A 
     CROSS JOIN LocationsB AS B
     GROUP BY A.ID) y ON x.aid = y.aid AND x.Distance = y.Distance

我们无法回避这样一个事实,即必须将A中的每条记录与B中的每条记录进行比较,如果A和B都包含大量记录,那么很明显,这将很难扩展

也就是说,这将返回正确的结果:

SELECT aid, bid, distanceAB
FROM (
  SELECT aid, bid, distanceAB,
    dense_rank() over (partition by aid order by distanceAB) as n
  FROM (
    SELECT a.id as aid, B.id as bid,
      acos(sin(radians(A.lat)) * sin(radians(B.lat)) +
        cos(radians(A.lat)) * cos(radians(B.lat)) *
        cos(radians(A.lon - B.lon))) * 6372.8 as distanceAB
    FROM A cross join B
  ) C
) D
WHERE n = 1
如果您的集合不太大,这将在合理的时间内返回。A中有3个位置,B中有130000左右,在我的机器上大约需要1秒。1000条记录每一条大约需要40秒。就像我说的,它的伸缩性很差

应该注意的是,Sparky的回答在某些情况下可能返回不正确的结果。假设你的A位置是+40,+100+40,+111不会被返回,即使它比+49,+109更接近