如何查询坐标5英里范围内的所有行?

时间:2015-09-15 00:38:53

标签: sql postgresql indexing postgis

这是我的CSV格式的PostgreSQL示例。

row,latitude,longitude
1,42.082513,-72.621498
2,42.058588,-72.633386
3,42.061118,-72.631541
4,42.06035,-72.634145

我在全世界范围内拥有数千个像这些跨越坐标的行。

我想仅查询表中某个半径范围内的坐标。如何使用PostGIS和PostgreSQL执行此操作?

2 个答案:

答案 0 :(得分:9)

您希望"坐标半径5英里范围内的所有行" ,因此恰好是K-nearest-neighbour (KNN) problem。相关,但你的情况更简单。 "找到离我坐标最近的10行" 将是一个KNN问题。

将坐标转换为geography值:

ST_SetSRID(ST_MakePoint(longitude, latitude),4326)::geography

或者,您可以使用更简单的geometry类型。试想一下:
4.2.2. When to use Geography Data type over Geometry data type

然后我们有一个像这样的表:

CREATE TABLE tbl (
  tbl_id serial PRIMARY KEY
, geog geography NOT NULL
);

您需要的只是ST_DWithin() - 和空间索引,以加快速度:

CREATE INDEX tbl_geog_gist ON tbl USING gist(geog);

查询:

SELECT *, ST_Distance(c.x, geog) AS distance  -- distance is optional
FROM   tbl t, (SELECT ST_GeographyFromText('SRID=4326;POINT(-72.63 42.06)')) AS c(x)
WHERE  ST_DWithin(c.x, geog, 8045)  -- distance in meter
ORDER  BY distance; -- order is optional, you did not ask for that

您可以使用原始列并创建功能索引... 关于dba.SE这个密切相关的答案中的这个和其他细节:

答案 1 :(得分:3)

您应首先使用COPY command(如果文件可供PostgreSQL 服务器访问)或\copy command Reverse Geocoding in Python Geocoder从CSV格式的文件创建表格。 1}}如果文件不是服务器的本地文件。如果您遇到任何问题,请参阅SO上的其他Q + A.

在表格中显示数据后,您应将psqllongitude列转换为PostGIS latitude类型,方法是在{{1}类型的表格中添加一列然后使用适当的值填充该列(此处称为geography):

geography(POINT, 4326)

在该列上添加索引以便进行有效搜索:

gps

现在,您可以找到距离指定位置5英里范围内的行,例如UPDATE my_table SET gps = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326); ,如下:

CREATE INDEX my_table_gps ON my_table USING gist(gps);

请注意,(-72.657, 42.0657)列上的SELECT * FROM my_table WHERE ST_DWithin(gps, ST_SetSRID(ST_MakePoint(-72.657, 42.0657), 4326), 5 * 1609); 将以米为单位,因此您必须将英里半径乘以一英里的1,609米。