如何查询坐标 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 中获得数据后,您应该将 longitude
和 latitude
列转换为 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);
这是 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 中获得数据后,您应该将 longitude
和 latitude
列转换为 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);