有没有办法比较两个表的纬度/经度

问题描述

我有两个表:

  • address_points

  • kmldata

    address_points table columns:    ID         address    Latitude1      Longitude2
    kmldata table columns:           Locname    Lat        Long
    

现在,我想查看address_points表的所有记录,这些记录的Latitude1和Longitude2值都在kmldata表的Lat和Long值范围内。

我以前没有在sql Server中处理过位置比较,所以不知道在这里可以使用哪个功能。我想到了 BETWEEN 运算符,但似乎可以在这里正确使用它。关于如何实现此目标的任何指导?

解决方法

您需要在SQL Server中使用空间功能。首先,您需要汇总kmldata表中的所有点以创建一个区域,然后使用STWithin检查哪些点属于该区域:

declare @kmlarea geography

select @kmlarea = geography::EnvelopeAggregate(geography::Point(Lat,Long,4326))
from kmldata

select *
from address_points a
where geography::Point(Latitude1,Longitude2,4326).STWithin(@kmlarea) = 1
,

有两种方法可以计算两组坐标之间的地理距离。内置的地理方法已经发布。还有一些基于圆形地球模型的良好“自家种植”功能。

当源表和目标表中的行数很多时,困难的部分是进行实际比较。将每个来源与每个目的地进行比较会产生不必要的大笛卡尔积。我之所以说“不必要”,是因为当我只对距源15英里的目的地感兴趣时,计算佛罗里达州与加利福尼亚目的地之间的距离毫无意义。

为解决该问题,我创建了一个“边界框”功能,该功能可围绕一组坐标计算一个正方形的框。该代码发布在下面...

CREATE FUNCTION dbo.tfn_LatLngBoundingBox
/* ===================================================================
12/03/2019 JL,Created: Calculates the bounding box for a given set of Lat/Lng coordinates.
=================================================================== */
--===== Define I/O parameters
(
    @Lat DECIMAL(8,5),@Lng DECIMAL(8,@MaxDistance DECIMAL(8,3),@DistanceUnit CHAR(1)       -- 'M'=miles ; 'K'=kilometers
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
    SELECT 
        MinLat = CONVERT(decimal(8,(x.MinLat / PI()) * 180),MaxLat = CONVERT(decimal(8,(x.MaxLat / PI()) * 180),MinLng = CONVERT(decimal(8,(y.MinLng / PI()) * 180),MaxLng = CONVERT(decimal(8,(y.MaxLng / PI()) * 180)
    FROM
        ( VALUES (
                CASE 
                    WHEN @DistanceUnit = 'K' THEN @MaxDistance / 6366.707019    -- Earth sphere radius in kilometers
                    WHEN @DistanceUnit = 'M' THEN (@MaxDistance * 1.609344) / 6366.707019
                END,(@Lat / 180) * PI(),(@Lng / 180) * PI()
                ) ) r (DistRad,rLat,rLng)
        CROSS APPLY ( VALUES (r.rLat - r.DistRad,r.rLat + r.DistRad) ) x (MinLat,MaxLat)
        CROSS APPLY ( VALUES (ASIN(SIN(r.rLat) / COS(r.DistRad))) ) lt (LatT)       -- = 1.4942 rad
        CROSS APPLY ( VALUES (ACOS( ( COS(r.DistRad) - sin(lt.LatT) * sin(r.rLat) ) / ( cos(lt.LatT) * cos(r.rLat) ) ) ) ) dl (DeltaLng)
        CROSS APPLY ( VALUES (r.rLng - dl.DeltaLng,r.rLng + dl.DeltaLng) ) y (MinLng,MaxLng);
GO

用例如下所示...

SELECT
    s.Lat,s.Lng,d.Lat,d.Lng,dm.DistanceInMiles  
FROM
    dbo.[Source] s
    CROSS APPLY dbo.tfn_LatLngBoundingBox(s.Lat,15,'M') bb
     LEFT JOIN dbo.Destination d
        ON d.lat BETWEEN bb.MinLat AND bb.MaxLat
        AND d.Lng BETWEEN bb.MinLng AND bb.MaxLng
    CROSS APPLY dbo.tfn_LatLonDistanceInMiles(s.Lat,d.Lng) dm    
WHERE 
    dm.DistanceInMiles <= 15;