问题 基于纬度经度进行半径搜索的SQL查询


我们有一个餐厅餐桌,每行有一个lat-long数据。

我们需要编写一个执行搜索的查询来查找所提供半径内的所有餐馆,例如1英里,5英里等

为此,我们有以下查询:

***Parameters***

Longitude: -74.008680
Latitude: 40.711676
Radius: 1 mile

***Query***

SELECT *
FROM restaurant
WHERE (
POW( ( 69.1 * ( Longitude - -74.008680 ) * cos( 40.711676 / 57.3 ) ) , 2 ) + POW( ( 69.1 * ( Latitude - 40.711676 ) ) , 2 )
) < ( 1 *1 );

该表有大约23,000行。结果集的大小有时很奇怪,例如对于5.4英里的搜索,它返回880行,对于5.5英里,它返回21k行。

此表包含nyc的餐馆数据 - 因此实际分布不符合结果集。

问题:是否有任何错误使用此查询?

DB:MySQL,经度:DECIMAL(10,6),纬度:DECIMAL(10,6)


2028
2017-11-13 04:31


起源

怎么了?对于初学者,您希望使用UTM而不是Lat / Long坐标,因为它们具有较小的平坦误差范围...... - OMG Ponies
看看答案 这个问题。类似的问题。 - Ramin


答案:


这有什么不妥吗?   查询?

在我看来,由于所涉及的数学,WHERE子句将会很慢,并且在WHERE子句中使用函数将阻止数据库使用索引来加速查询 - 因此,实际上,您将检查数据库,并在每次进行查询时对每一行执行大圆数学运算。

就个人而言,我会计算一个正方形的TopLeft和BottomRight坐标(只需要用毕达哥拉斯进行粗略计算),其边长等于你要查找的范围,然后对较小的子集执行更复杂的WHERE子句测试。在Lat / Long方格内的记录。

在数据库中使用Lat&Long索引查询

在哪里MyLat> = @MinLat和MyLat <= @MaxLat
      AND MyLong> = @MinLong和MyLong <= @MaxLong

应该非常有效率

(请注意,我不知道MySQL,只有MS SQL)


13
2017-11-13 16:43



另见: janmatuschek.de/LatitudeLongitudeBoundingCoordinates - Pete


您可能想要创建一个 SPATIAL 您的表上的索引,以使搜索更快。

为此,请添加 POINT 列到你的表:

ALTER TABLE restaurant ADD coords POINT NOT NULL;

CREATE SPATIAL INDEX sx_restaurant_coords ON restaurant (coords);

SELECT  *
FROM    restaurant
WHERE   MBRContains(coords, LineString(Point(583734 - 1609, 4507223 - 1609), Point(583734 + 1609, 4507223 + 1609))
        AND GLength(LineString(Point(583734, 4507223), coords)) <= 1609

你应该存储 coords 如 UTM 单个区域内的坐标。


3
2017-11-13 16:23





使用一个函数,例如唯一的那个 我发布在这里

然后,查询您的餐馆,例如获得5英里半径范围内的所有内容

select * from restaurants 
  where dbo.udf_Haversine(latitude, longitude, @lat, @long) < 5

这适用于邮政编码数据。


0
2017-12-08 04:39





如果您的数据在SQL Server数据库中,则可以使用以下命令:

CREATE PROC up_FindZipCodesWithinRadius

    @ZipCode char(5) ,
    @GivenMileRadius int
AS
SET NOCOUNT ON

DECLARE @lat1 float, 
    @long1 float

SELECT  @lat1= latitude,
    @long1 = longitude 
FROM ZipSource
WHERE zipcode = @ZipCode

SELECT ZipCode ,DistanceInMiles
FROM
(
    SELECT  ZipCode,3958.75 * ( Atan(Sqrt(1 - power(((Sin(@Lat1/57.2958) * Sin(latitude/57.2958)) + 
            (Cos(@Lat1/57.2958) * Cos(latitude/57.2958) * Cos((longitude/57.2958) - (@Long1/57.2958)))), 2)) / 
            ((Sin(@Lat1/57.2958) * Sin(latitude/57.2958)) + (Cos(@Lat1/57.2958) * Cos(latitude/57.2958) * 
            Cos((longitude/57.2958) - (@Long1/57.2958)))))) as DistanceInMiles
FROM ZipSource
) a
WHERE a.DistanceInMiles <= @GivenMileRadius
--AND ZipCode <> @ZipCode
ORDER BY DistanceInMiles

GO

EXEC up_FindZipCodesWithinRadius '35085',20
GO

DROP PROC up_FindZipCodesWithinRadius

0
2017-11-20 03:58