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

12
给定一个包含三个字段的数据库:
纬度 经度 接近度
其中 Lat和Long是GPS坐标,而Proximity表示与之接近的距离(以什么单位计算-英尺?或者秒?或者分钟?)。
并且已知用户当前的GPS纬度/经度...
我想写一个SQL查询,以检索所有在"Proximity"范围内的行。
关键:这必须在SQLite中工作,因为它只支持相当原始的数据类型。不能欺骗并依赖于SQL Server(或提供更好的地理空间函数的其他产品)。
有什么建议吗?

你不能使用简单的SQL计算两点之间的距离,然后查看是否小于该距离吗?简单的欧几里得几何学? - Thomas
2
@Thomas:两点之间的欧几里得距离是通过地球上的一条直线。这可能不是你想要的。 - dan04
2
@dan04 地球的周长比任何搜索半径都要大得多,因此可以忽略不计。100英里到99.88英里,大约是630英尺,少于一个足球场的长度。 - Gallonallen
3个回答

7

这里是一个基于C语言的自定义sqlite函数[从下面提供的链接中复制而来]。它可以在iOS应用程序中使用。它假设你有名为latitude和longitude的列,并计算它们与你提供的任何纬度/经度坐标之间的差异。非常好的写作,可直接使用。

#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);
}

This defines an SQL function distance(Latitude1, Longitude1, Latitude2, Longitude2), which returns the distance (in kilometres) between two points.

To use this function, add the code above ... and then add this line immediately after you call sqlite3_open:

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

…where sqliteDatabasePtr is the database pointer returned by your call to sqlite3_open.

Assuming you have a table called Locations, with columns called Latitude and Longitude (both of type double) containing values in degrees, you can then use this function in your SQL like this:

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

This example orders the locations in your database based on how far away they are from the London Eye, which is at 51.503357, -0.1199.

编辑:

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


注:本文介绍了如何使用存档页面找回失效的网页。

1
总有“wayback机器”的(https://web.archive.org/web/20160808122817/http://www.thismuchiknow.co.uk/?p=71) - mvandillen

3

2
你也知道SQLite有一个名为Spatialite的插件,它具有与PostGIS和SQLServer相同的所有功能吗?我猜你正在尝试在iPhone或浏览器中使用SQLite。如果不是的话,我强烈推荐使用Spatialite。

是的,我在做iPhone开发。找到了http://www.thismuchiknow.co.uk/?p=71这个网址,打算试试看。 - Don Jones

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接