有没有办法比较两个表的 Lat/long
Is there a way to compare Lat/long of two tables
我有两个 table:
address_points
kmldata
address_points table columns: ID address Latitude1 Longitude2
kmldata table columns: Locname Lat Long
现在我想查看address_pointstable的Latitude1和Longitude2值在kmldatatable的Lat和Long值范围内的所有记录table。
我以前没有在 SQL 服务器中处理过位置比较,所以不知道我可以在这里使用哪个功能。我想到了 BETWEEN 运算符,但似乎可以在这里正确使用它。关于如何实现此目标的任何指导?
您需要使用 SQL 服务器内的空间功能。首先,您需要汇总 kmldata
table 中的所有点以创建一个区域,然后使用 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,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;
我有两个 table:
address_points
kmldata
address_points table columns: ID address Latitude1 Longitude2 kmldata table columns: Locname Lat Long
现在我想查看address_pointstable的Latitude1和Longitude2值在kmldatatable的Lat和Long值范围内的所有记录table。
我以前没有在 SQL 服务器中处理过位置比较,所以不知道我可以在这里使用哪个功能。我想到了 BETWEEN 运算符,但似乎可以在这里正确使用它。关于如何实现此目标的任何指导?
您需要使用 SQL 服务器内的空间功能。首先,您需要汇总 kmldata
table 中的所有点以创建一个区域,然后使用 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,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;