根据用户的位置查询数据库值

时间:2014-08-06 21:05:03

标签: javascript php mysql geospatial postgis

如何根据用户的位置值对数据库执行查询?该应用程序是使用HTML5,CSS,Javascript开发的,PHP有一个带有列的数据库,如下表所示。

database structure

在html网页上收集用户地理坐标,并将其与数据库中的值进行比较,以找到用户与数据库中的位置最近的位置。

请告诉我如何实现这一目标。任何示例/样本将不胜感激。

2 个答案:

答案 0 :(得分:3)

有一个问题可以比较各种空间数据库GIS: PostGIS/PostgreSQL vs. MySql vs. SQL Server?的功能,其中Postgis比MySQL更胜一筹。

无论您使用的是MySQL还是Postgis,如果可以的话,最好还是将纬度和经度值存储为几何/地理(Point),作为可用于查找附近事物的函数,{{ 3}},ST_Distance以及更加模糊的ST_Distance_Sphere,请参阅<-> operator(例如用法)直接在几何/地理列上工作。更重要的是,您可以添加空间索引,这些功能需要正常工作,这将大大超过单独索引的纬度和经度列上的搜索(这将取决于表大小,但随着表格大小的增长而增长),

在Postgis中,您可以使用以下符号将lat和lon转换为几何体

alter table mytable add column geom (Geometry, 4326);
update mytable set geom = ST_SetSRID(ST_MakePoint(lon, lat), 4326)
create index ix_spatial_mytable_geom on mytable using gist(geom);

此时,您可以使用上述链接中的任何示例,通过非常有效的查询来查找其他点附近的点。

你可以在MySQL中做类似的事情,虽然它不支持空间参考系统,即上面的4326,这意味着lat / lon,它缺少ST_MakePoint函数,所以你需要使用STGeomFromText并连接lat / lon一起制作一个POINT。正如Claudio和其他人所说的那样,它也可以做平面坐标中的所有事情,这与Postgis不是一个问题。

我为一个长期而且有些切合实际的答案道歉,但是在大量数据(MySQL,SQL Server和Postgres / GIS)的数据库之间进行了各种迁移,并在途中犯了很多错误,我希望我能为你做好准备朝着正确的方向前进(并添加一些未来的证明,如果你想开始使用一些其他的空间功能,Postigs在黑桃中)。

答案 1 :(得分:2)

对于粗略的测量,我会尝试类似下面的东西(只有欧几里德几何,它没有考虑地球曲率或这样的问题)。

首先,您可以计算用户坐标与数据库中地点坐标之间的差异。像这样:

distLat = abs(userLat - placeLat)
distLong = abs(userLong - placeLong)

然后我会用毕达哥拉定理计算两点之间的距离。所以:

distance = squareRoot(distLat * distLat + distLong * distLong)

您可以比较数据库中所有地点的距离并采用最小值,teoreticaly是距离用户最近的位置。

如果您使用MySQL,我认为像这样的查询应该有效:

SELECT * FROM places ORDER BY MIN(SQRT((p.latitude - userLatitude) * (p.latitude - userLatitude) + (p.longitude - userLongitude) * (p.longitude - userLongitude))) LIMIT 1

请注意,根据您拥有的位置,此查询可能会非常慢,因为它需要读取表中的所有行并计算每个行的距离。索引没有效果。

无论如何,对于这类问题,您最好使用具有良好地理空间扩展的GIS或数据库。即使在MySQL 5.6中,MySQL地理空间扩展也不是很强大。它具有ST_DISTANCE函数,但仍然使用欧几里德几何,这对于像地球这样的球面上的计算不是很准确。无论如何,如果你使用MySQL 5.6,我认为使用ST_DISTANCE函数应该更好,这肯定比计算更加优化&#34;手动&#34;在查询中。

另见本文的深入解释和更多示例:http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc

修改

根据OP的要求,我添加了有关如何处理负坐标的更多细节

负坐标通常不是一个大问题。我将尝试用一些例子来解释这一点。

以布鲁克林大桥的坐标为例:40.704391, -73.994675。 根据上面的公式,布鲁克林大桥与自由女神像的距离是:

sqrt((40.704391 - 40.689167)^2 + (-73.994675 - -74.044444)^2) = 0.052045399

现在考虑自由女神像和布鲁克林碗之间的距离(坐标40.7179666, -73.9670125),即:

sqrt((40.7179666 - 40.689167)^2 + (-73.9670125 - -74.044444)^2) = 0.082613886

正如您所看到的,布鲁克林碗与自由女神像的距离大于布鲁克林大桥的距离。这是正确的,因为布鲁克林碗距离自由女神像有4英里,而布鲁克林大桥距离它只有1英里。

在这个例子中,这两个点都有负经度。但即使两者中的一个具有正坐标,该公式仍然有效。例如,自由女神像和埃菲尔铁塔(巴黎,坐标48.858360, 2.294460)之间的距离是:

 sqrt((48.858360 - 40.689167)^2 + (2.294460 - -74.044444)^2) = 76.77476134

然后计算自由女神像和罗马斗兽场(罗马,坐标41.890238, 12.492242)之间的距离:

sqrt((41.890238 - 40.689167)^2 + (12.492242 - -74.044444)^2) = 86.54502063

正如你所看到的那样,罗马斗兽场的距离更远,因为距离自由女神像大约8000公里,而埃菲尔铁塔距离大约800公里。

我看到的唯一问题是你必须分别计算远东和远西两个地方之间的距离。上面的公式会给你一个很高的距离,但实际上它们可能非常接近。以阿拉斯加的安克雷奇(坐标61.252240, -149.896769)和俄罗斯东部的城市Beringovskij(坐标63.049797, 179.310011)为例。它们的距离只有1500公里左右,但按照上面的公式得到:

sqrt((61.252240 - 63.049797)^2 + (-149.896769 - 179.310011)^2) = 329.2116875

绝对是一个只有1500公里的太高的值:我会期望小于50的东西。

问题是公式计算以中央子午线为参考点的距离,即纬度为0度的子午线。这是好的,直到距离<#34; 不再是地球的一半&#34;。

我认为解决方案可能是计算两个距离。 第一个参考点为0度:这是上述公式的作用。 第二个参考点为180度。这就像计算移动180度的世界地图上的距离一样,如下所示:http://www.bouwman.com/world/Formilab-180.html。 然后取这两个距离中的最小值。

因此公式变得有点复杂:

distance = squareRoot(min((userLat - placeLat)^2, (userLat - placeLat - 360)^2) + (userLong - placeLong)^2)

请注意,我们减去360,因为它是-180度和180度之间的距离。

使用这个新公式,我们可以获得距离彼此相差180度以上的地方的正确结果,并且当比较彼此相差小于180度的地方时,我们也得到前一公式给出的相同结果。计算距离安克雷奇 - Beringovskij现在是:30.84564166

当然,正如我已经说过的,这不是计算距离的精确方法。你可以看看这篇文章了解更多&#34;科学&#34;技巧:https://en.wikipedia.org/wiki/Geographical_distance:D