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

How do I query all rows within a 5-mile radius of my coordinates?

这是 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

我还有数千行像这些横跨世界的坐标。

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

你想要 "all rows within a 5-mile radius of a coordinate",所以这 不是 正好是 K-nearest-neighbour (KNN) problem。相关,但你的情况更简单。 "Find the 10 rows closest to my coordinates" 将是一个 KNN 问题。

将您的坐标转换为 geography 值:

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

或者您可以使用更简单的 geometry 类型。考虑:
4.2.2. When to use Geography Data type over Geometry data type

然后我们有一个 table 比如:

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 上这个密切相关的答案中的这个和其他细节:

您应该首先从您的 CSV 格式文件创建一个 table,如果该文件不在服务器本地,则使用 psql 中的 COPY command (if the file is accessible to the PostgreSQL server) or the \copy command。如果您有任何问题,请参阅关于 SO 的其他 Q+A 示例。

在 table 中获得数据后,您应该将 longitudelatitude 列转换为 PostGIS geography 类型,方法是向 table 类型 geography(POINT, 4326),然后用适当的值填充该列(此处称为 gps):

UPDATE my_table SET gps = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326);

在该列上添加索引以实现高效搜索:

CREATE INDEX my_table_gps ON my_table USING gist(gps);

您现在可以找到距给定位置 5 英里范围内的行,例如(-72.657, 42.0657),如下:

SELECT *
FROM my_table
WHERE ST_DWithin(gps, ST_SetSRID(ST_MakePoint(-72.657, 42.0657), 4326), 5 * 1609);

请注意,geography 列中的 ST_DWithin() 以米为单位,因此您必须将半径(以英里为单位)乘以 1,609 米(以英里为单位)。

我结合了欧文和帕特里克的答案。

-- Add geography column
ALTER TABLE googleplaces ADD COLUMN gps geography;
UPDATE googleplaces SET gps = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326);
CREATE INDEX googleplaces_gps ON googleplaces USING gist(gps);

SELECT *
FROM my_table
WHERE ST_DWithin(gps, ST_SetSRID(ST_MakePoint(-72.657, 42.0657), 4326), 5 * 1609);