给定纬度/经度的基于距离的JOIN

Mar*_*ace 5 sql t-sql join distance haversine

给出以下表格:

table A (id, latitude, longitude)
table B (id, latitude, longitude)
Run Code Online (Sandbox Code Playgroud)

如何构建一个高效的T-SQL查询,将A中的每一行与B中最近的行相关联?

ResultSet应该包含A中的所有行,并将它们与1和B中的1个元素相关联.我正在寻找的格式如下:

(A.id, B.id, distanceAB)
Run Code Online (Sandbox Code Playgroud)

我有一个函数来计算给定2对纬度和经度的距离.我尝试使用order by ... limit 1和/或尝试的东西,rank() over (partition by ...) as rowCount ... where rowCount = 1但结果要么不是我需要的,要么返回需要太长时间.

我错过了什么吗?

Cha*_*had 5

没有办法绕过这样一个事实:你必须将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
Run Code Online (Sandbox Code Playgroud)

如果您的套装不是太大,这将在合理的时间内返回.A中有3个位置,B中有130,000个左右,我的机器上需要大约一秒钟.每篇1000条记录大约需要40秒.就像我说的那样,它的扩展性很差.

应该注意的是,Sparky的答案在某些情况下可能会返回错误的结果.假设您的A位置为+ 40,+ 100.即使它比+ 49,+ 109更接近,也不会返回+ 40,+ 111.


Spa*_*rky 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
Run Code Online (Sandbox Code Playgroud)

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