【问题标题】:SQL Query for Performing Radius Search based on Latitude Longitude基于经纬度进行半径搜索的SQL查询
【发布时间】:2010-12-16 04:13:27
【问题描述】:

我们有一个restaurant 表,其中每一行都有经纬度数据。

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

为此,我们有以下query

***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 );

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

此表包含纽约市的餐厅数据 - 因此实际分布与结果集不同。

问题:这个查询有什么问题吗?

数据库:MySQL,经度:DECIMAL(10,6),纬度:DECIMAL(10,6)

【问题讨论】:

  • 怎么了?对于初学者,您希望使用 UTM 而不是纬度/经度坐标,因为它们的展平误差较小...
  • 查看this question 的答案。类似的问题。

标签: iphone sql mysql geolocation latitude-longitude


【解决方案1】:

如果你的数据在 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

【讨论】:

    【解决方案2】:

    使用函数,例如那个I posted here

    然后,查询您的餐厅,例如获取方圆 5 英里范围内的所有内容

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

    这适用于邮政编码数据。

    【讨论】:

      【解决方案3】:

      这有什么问题吗 查询?

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

      我个人会计算一个正方形的 TopLeft 和 BottomRight 坐标(只需要使用毕达哥拉斯进行粗略计算),其边等于您正在寻找的范围,然后在该纬度/经度正方形内的较小记录子集。

      使用数据库中的经纬度索引进行查询

      其中 MyLat >= @MinLat AND MyLat = @MinLong AND MyLong

      应该很高效

      (请注意,我不了解 MySQL,只了解 MS SQL)

      【讨论】:

        【解决方案4】:

        您可能希望在您的表上创建一个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 在单个区域内的坐标。

        【讨论】:

          猜你喜欢
          • 2013-03-15
          • 1970-01-01
          • 1970-01-01
          • 2020-10-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多