【问题标题】:Is there a way to compare Lat/long of two tables有没有办法比较两个表的纬度/经度
【发布时间】:2020-09-23 17:05:37
【问题描述】:

我有两张桌子:

  • 地址点

  • kml数据

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

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

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

【问题讨论】:

  • 请添加示例数据和预期结果。
  • “kmldata 表的经纬度值范围”是什么意思?您的意思是纬度和经度与 kmldata 表中保存的值完全匹配,还是 kmldata 表中的所有点都描述了您希望 address_points 值落在其中的区域?
  • @strickt01 是的,这是正确的“kmldata 表中的点描述了您希望 address_points 值落入的区域?”

标签: sql sql-server coordinates between spatial-query


【解决方案1】:

您需要使用 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

【讨论】:

  • 你确定使用 stwithin 方法,因为它说找不到类型的方法 stwithin...我使用的是 sql server 2014
  • 即使查询运行成功
  • @zainulabidin 您可以使用STIntersects 来避免SSMS 中的警告,但它们会给您相同的结果。 STWithin 有效 - docs.microsoft.com/en-us/sql/t-sql/spatial-geography/….
【解决方案2】:

有几种方法可以计算两组坐标之间的地理距离。已经发布的是内置的地理方法。还有几个很好的基于圆形地球模型的“本土”功能。

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

为了解决这个问题,我创建了一个“边界框”函数,它计算围绕一组坐标的正方形(ish)框。代码贴在下面...

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,5),
    @MaxDistance DECIMAL(8,3),
    @DistanceUnit CHAR(1)       -- 'M'=miles ; 'K'=kilometers
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
    SELECT 
        MinLat = CONVERT(decimal(8, 5), (x.MinLat / PI()) * 180),
        MaxLat = CONVERT(decimal(8, 5), (x.MaxLat / PI()) * 180),
        MinLng = CONVERT(decimal(8, 5), (y.MinLng / PI()) * 180),
        MaxLng = CONVERT(decimal(8, 5), (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, s.Lng, 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, s.Lng, d.Lat, d.Lng) dm    
WHERE 
    dm.DistanceInMiles <= 15;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-12
    • 2021-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多