基于纬度/经度查询附近兴趣点的 SQL 查询 - SQLite

Posted

技术标签:

【中文标题】基于纬度/经度查询附近兴趣点的 SQL 查询 - SQLite【英文标题】:SQL query to query nearby points of interest based on lat/long - SQLite 【发布时间】:2010-07-02 20:24:07 【问题描述】:

给定一个包含三个字段的数据库:

纬度 经度 接近度

Lat 和 Long 是 GPS 坐标,Proximity 是(一些单位 - 英尺?秒?分钟?)

并且给定用户当前的 GPS 纬度/经度...

我想编写一个 SQL 查询,该查询将检索用户在这些行的“邻近”范围内的所有行。

还有诀窍:这必须在 SQLite 中工作,它只支持相当原始的数据类型。不作弊,不依赖 SQL Server(或其他提供更好地理空间功能的产品)。

有什么建议吗?

【问题讨论】:

你不能用一个简单的SQL来计算两点的距离,然后看看这是否小于这个距离?简单的欧几里得几何? @Thomas:两点之间的欧几里得距离沿着穿过地球的直线。这可能不是你想要的。 @dan04 地球的圆周比任何搜索半径都大,可以忽略不计。 100 英里到 99.88 英里,也就是大约 630 英尺,不到一个足球场。 【参考方案1】:

这是一个用于 sqlite 的基于 C 的自定义函数 [从下面提到的链接复制]。这可以在 ios 应用程序中使用。它假设您有名为纬度和经度的列,并计算它们与您提供的任何纬度/经度坐标之间的差异。优秀的文章,按原样工作。

#define DEG2RAD(degrees) (degrees * 0.01745327) // degrees * pi over 180

static void distanceFunc(sqlite3_context *context, int argc, sqlite3_value **argv)

  // check that we have four arguments (lat1, lon1, lat2, lon2)
  assert(argc == 4);
  // check that all four arguments are non-null
  if (sqlite3_value_type(argv[0]) == SQLITE_NULL || sqlite3_value_type(argv[1]) == SQLITE_NULL ||
  sqlite3_value_type(argv[2]) == SQLITE_NULL ||
  sqlite3_value_type(argv[3]) == SQLITE_NULL) 
  sqlite3_result_null(context);
  return;


// get the four argument values
double lat1 = sqlite3_value_double(argv[0]);
double lon1 = sqlite3_value_double(argv[1]);
double lat2 = sqlite3_value_double(argv[2]);
double lon2 = sqlite3_value_double(argv[3]);

// convert lat1 and lat2 into radians now, to avoid doing it twice below
double lat1rad = DEG2RAD(lat1);
double lat2rad = DEG2RAD(lat2);

// apply the spherical law of cosines to our latitudes and longitudes, and set the result appropriately

// 6378.1 is the approximate radius of the earth in kilometres
sqlite3_result_double(context, acos(sin(lat1rad) * sin(lat2rad) + cos(lat1rad) * cos(lat2rad) * cos(DEG2RAD(lon2) - DEG2RAD(lon1))) *
6378.1);

这定义了一个 SQL 函数 distance(Latitude1, Longitude1, Latitude2, Longitude2),返回距离(以公里为单位) 两点之间。

要使用此功能,请添加上面的代码 ... 和 然后在调用 sqlite3_open 后立即添加此行:

sqlite3_create_function(sqliteDatabasePtr, "distance", 4, SQLITE_UTF8, NULL, &distanceFunc, NULL, NULL);

…其中 sqliteDatabasePtr 是调用返回的数据库指针 到 sqlite3_open。

假设您有一个名为 Locations 的表,其中的列名为 纬度和经度(均为 double 类型),包含 度,然后你可以像这样在你的 SQL 中使用这个函数:

SELECT * FROM Locations ORDER BY distance(Latitude, Longitude, 51.503357, -0.1199)

此示例根据距离对数据库中的位置进行排序 距离伦敦眼,51.503357,-0.1199。

编辑:

原链接http://www.thismuchiknow.co.uk/?p=71已经失效,所以正如评论中提到的那样,你可以使用这个链接:https://web.archive.org/web/20160808122817/http://www.thismuchiknow.co.uk/?p=71来获取那个网页

【讨论】:

总是有wayback machine【参考方案2】:

Haversine formula 是您想要的。使用简单的欧几里得距离公式是不够的,因为地球的曲率会影响两点之间的距离。

Creating a Store Locator with php, mysql & Google Maps 是一篇关于用 MySQL 实现这个解决方案的文章,但是 SQLite 不支持三角函数。

在 Stack Overflow 上查看 Calculating Great-Circle Distance with SQLite 中的答案,了解有关扩展 SQLite 函数的更多提示,以便您解决这个问题。

【讨论】:

【参考方案3】:

您还知道有一个名为 Spatialite 的 SQLite 插件,它具有与 PostGIS 和 SQLServer 相同的功能?我假设您正在尝试在 iPhone 或浏览器或其他东西上使用 SQLLite。如果不是,我强烈推荐 spaceite。

【讨论】:

是的,正在做 iPhone。找到thismuchiknow.co.uk/?p=71,我要试试。

以上是关于基于纬度/经度查询附近兴趣点的 SQL 查询 - SQLite的主要内容,如果未能解决你的问题,请参考以下文章

将经度和纬度数据存储在数据库中,并查询附近的记录

MySQL:多个纬度和经度的附近位置

使用经度和纬度查找给定距离内的所有附近客户

在节点 js mysql 查询中传递经度和纬度和距离作为参数

SQL查询位置半径内的总点数

sql (mysql)怎么实现查询某一个经纬度周围500米距离的餐馆,数据库存放所有餐馆的经纬度?