鉴于以下数据,是否可能,如果是这样,这将是确定第一个表中“Shurdington”位置是否包含在第二个表中任何位置的给定半径内的最有效方法
GeoData列属于“地理”类型,因此使用SQL Server空间要素既可以选择也可以使用纬度和经度。
Location GeoData Latitude Longitude
===========================================================
Shurdington XXXXXXXXXX 51.8677979 -2.113189
ID Location GeoData Latitude Longitude Radius
==============================================================================
1000 Gloucester XXXXXXXXXX 51.8907127 -2.274598 10
1001 Leafield XXXXXXXXXX 51.8360519 -1.537438 10
1002 Wotherton XXXXXXXXXX 52.5975151 -3.061798 5
1004 Nether Langwith XXXXXXXXXX 53.2275276 -1.212108 20
1005 Bromley XXXXXXXXXX 51.4152069 0.0292294 10
非常感谢任何帮助。
答案 0 :(得分:9)
创建数据
CREATE TABLE #Data (
Id int,
Location nvarchar(50),
Latitude decimal(10,5),
Longitude decimal(10,5),
Radius int
)
INSERT #Data (Id,Location,Latitude,Longitude,Radius) VALUES
(1000,'Gloucester', 51.8907127 ,-2.274598 , 20), -- Increased to 20
(1001,'Leafield', 51.8360519 , -1.537438 , 10),
(1002,'Wotherton', 52.5975151, -3.061798 , 5),
(1004,'Nether Langwith', 53.2275276 , -1.212108 , 20),
(1005,'Bromley', 51.4152069 , 0.0292294 , 10)
<强>测试强>
将您的兴趣点声明为POINT
DECLARE @p GEOGRAPHY = GEOGRAPHY::STGeomFromText('POINT(-2.113189 51.8677979)', 4326);
要确定它是否在另一个点的半径内:
-- First create a Point.
DECLARE @point GEOGRAPHY = GEOGRAPHY::STGeomFromText('POINT(-2.27460 51.89071)', 4326);
-- Buffer the point (meters) and check if the 1st point intersects
SELECT @point.STBuffer(50000).STIntersects(@p)
将它们全部合并到一个查询中:
select *,
GEOGRAPHY::STGeomFromText('POINT('+
convert(nvarchar(20), Longitude)+' '+
convert( nvarchar(20), Latitude)+')', 4326)
.STBuffer(Radius * 1000).STIntersects(@p) as [Intersects]
from #Data
给出:
Id Location Latitude Longitude Radius Intersects
1000 Gloucester 51.89071 -2.27460 20 1
1001 Leafield 51.83605 -1.53744 10 0
1002 Wotherton 52.59752 -3.06180 5 0
1004 Nether Langwith 53.22753 -1.21211 20 0
1005 Bromley 51.41521 0.02923 10 0
回复:效率。通过一些正确的索引,可以看出SQL的空间索引非常快
答案 1 :(得分:1)
您可以计算两点之间的距离,并将此距离与给定半径进行比较。
为了计算短距离,您可以使用Wikipedia - Geographical distance - Spherical Earth projected to a plane处的公式,该公式声称“非常快并且可以为小距离产生相当准确的结果”。
根据公式,你需要纬度和经度的差异以及平均纬度
with geo as (select g1.id, g1.latitude as lat1, g1.longitude as long1, g1.radius,
g2.latitude as lat2, g2.longitude as long2
from geography g1
join geography g2 on g2.location = 'shurdington'
and g1.location <> 'shurdington')
base as (select id,
(radians(lat1) - radians(lat2)) as dlat,
(radians(long1) - radians(long2)) as dlong,
(radians(lat1) + radians(lat2)) / 2 as mlat, radius
from geo)
dist as (select id,
6371.009 * sqrt(square(dlat) + square(cos(mlat) * dlong)) as distance,
radius
from base)
select id, distance
from dist
where distance <= radius
我使用with select
作为中间步骤来保持计算“可读”。
答案 2 :(得分:1)
如果你想自己做数学,你可以使用基于毕达哥拉斯的Equirectangular近似。公式是:
var x =(lon2-lon1)* Math.cos((lat1 + lat2)/ 2); var y =(lat2-lat1); var d = Math.sqrt(x * x + y * y)* R;
就SQL而言,这应该为您的第二个表中的那些位置提供在其半径范围内包含您的条目的位置:
SELECT *
FROM Table2 t2
WHERE EXISTS (
SELECT 1 FROM Table1 t1
WHERE
ABS (
SQRT (
(SQUARE((RADIANS(t2.longitude) - RADIANS(t1.longitude)) * COS((RADIANS(t2.Latitude) + RADIANS(t1.Latitude))/2))) +
(SQUARE(RADIANS(t1.Latitude) - RADIANS(t2.Latitude)))
) * 6371 --Earth radius in km, use 3959 for miles
)
<= t2.Radius
)
请注意,这不是最准确的方法,但可能还不错。如果你正在寻找遍布全球的距离,你可能希望采用谷歌的'hasrsine'公式。
将此与Paddy的解决方案进行比较可能值得一看,看看他们的表现如何以及哪种表现最佳。