使用postGIS添加点和计算英里距离的正确方法
Correct way to add points and calculate distances in miles using postGIS
我是 PostGIS 的新手,想在我的数据库中为一个新的地方创建一个列来存储它的纬度和经度(一个 2D 点)。稍后我会希望能够找到这两点之间的距离。
看来我可以通过 运行 以下查询来完成我想要的:
CREATE EXTENSION postgis;
CREATE TABLE places (
id SERIAL PRIMARY KEY,
name VARCHAR(500) NOT NULL,
location geometry NOT NULL
);
INSERT INTO places (name, location)
VALUES ('The Place of Luke', ST_SetSRID(ST_MakePoint(-71.1043443253471, 42.3150676015829),4326)),
('The Place of Bob', ST_SetSRID(ST_MakePoint(-75.1043443253471, 43.3150676015829),4326));
SELECT ST_Distance(
(SELECT location FROM places WHERE name = 'The Place of Luke'),
(SELECT location FROM places WHERE name = 'The Place of Bob')
);
我相信这会正确返回 4.12310562561766
的纬度和经度距离,但我有几个关于最佳实践的问题。
geometry
是我要完成的任务的正确类型吗?我尝试将 geometry
更改为 point
:
CREATE TABLE places (
id SERIAL PRIMARY KEY,
name VARCHAR(500) NOT NULL,
location point NOT NULL
);
INSERT INTO places (name, location)
VALUES ('The Place of Luke', ST_MakePoint(-71.1043443253471, 42.3150676015829)),
('The Place of Bob', ST_MakePoint(-75.1043443253471, 43.3150676015829));
SELECT ST_Distance(
(SELECT location FROM places WHERE name = 'The Place of Luke'),
(SELECT location FROM places WHERE name = 'The Place of Bob')
);
但我一直在 ERROR: column "location" is of type point but expression is of type geometry
。我知道 ST_MakePoint 可能正在尝试创建类型为 geometry
的东西,这是导致错误的原因,但是我该如何创建类型为 point?
的东西
- documentation 似乎非常坚持我应该使用
AddGeometryColumn()
而不是直接将列添加到我的位置 table,但我不明白为什么以及是否会这样随着我的应用程序的增长成为一个问题。如果我需要做的只是找到两个地方(在二维平面上)之间的距离作为陆地旅行距离,这对我来说会有问题吗?
- 如何将此结果转换为英里(可能还有公里)。我应该 运行 一起成为不同的查询吗?我对经纬度的理解让我认为返回的这个数字不会是英里的简单线性转换。
我建议使用
- 使用
geography(Point,4326
) 作为位置的数据类型
- 查询为
ST_Distance(location1::geography, location2::geography)
通过转换为 geography
数据类型,结果为 meters
,而不是度数,这将毫无意义。请注意,4326 与 WGS84 是同一系统(大多数 GPS 数据所参考的系统)
另请参阅此 Q/A 了解更多详情:
https://gis.stackexchange.com/questions/76967/what-is-the-unit-used-in-st-distance
编辑:
回复:AddGeometryColumn
不需要使用该功能,这只是一种方便 - 据我所知。
编辑:
补充说明,不是你问的,但postgis中也有空间索引类型:
CREATE INDEX loc_idx ON places USING gist (location);
- 是的,如果您使用的是 PostGIS,请不要使用
point
。 Point 是原生类型。 PostGIS 是一个扩展,可以做你想做的事。如果一切都在4326,你应该看看geography
类型并使用它。
- 切勿使用
AddGeometryColumn()
,除非您使用的是 PostGIS 1.x。 PostGIS 2.x 支持类型修饰符,您可以使用 ALTER TABLE
代替。
- 要使用获取里程,只需 return 公里和
* 0.621371192
这有点奇怪,但很实用。
SELECT ST_Distance(
(SELECT location FROM places WHERE name = 'The Place of Luke'),
(SELECT location FROM places WHERE name = 'The Place of Bob')
);
通常您会在批量处理的 JOIN 中看到它,但它也可以按照您的预期在相关子查询中使用。
SELECT
l1.location,
l2.location,
ST_Distance( l1.location, l2.location )
FROM location AS l1
JOIN location AS l2
ON l2.location = 'The Place of Luke'
WHERE places = 'The Place of Bob';
我是 PostGIS 的新手,想在我的数据库中为一个新的地方创建一个列来存储它的纬度和经度(一个 2D 点)。稍后我会希望能够找到这两点之间的距离。
看来我可以通过 运行 以下查询来完成我想要的:
CREATE EXTENSION postgis;
CREATE TABLE places (
id SERIAL PRIMARY KEY,
name VARCHAR(500) NOT NULL,
location geometry NOT NULL
);
INSERT INTO places (name, location)
VALUES ('The Place of Luke', ST_SetSRID(ST_MakePoint(-71.1043443253471, 42.3150676015829),4326)),
('The Place of Bob', ST_SetSRID(ST_MakePoint(-75.1043443253471, 43.3150676015829),4326));
SELECT ST_Distance(
(SELECT location FROM places WHERE name = 'The Place of Luke'),
(SELECT location FROM places WHERE name = 'The Place of Bob')
);
我相信这会正确返回 4.12310562561766
的纬度和经度距离,但我有几个关于最佳实践的问题。
geometry
是我要完成的任务的正确类型吗?我尝试将geometry
更改为point
:CREATE TABLE places ( id SERIAL PRIMARY KEY, name VARCHAR(500) NOT NULL, location point NOT NULL ); INSERT INTO places (name, location) VALUES ('The Place of Luke', ST_MakePoint(-71.1043443253471, 42.3150676015829)), ('The Place of Bob', ST_MakePoint(-75.1043443253471, 43.3150676015829)); SELECT ST_Distance( (SELECT location FROM places WHERE name = 'The Place of Luke'), (SELECT location FROM places WHERE name = 'The Place of Bob') );
但我一直在
ERROR: column "location" is of type point but expression is of type geometry
。我知道 ST_MakePoint 可能正在尝试创建类型为geometry
的东西,这是导致错误的原因,但是我该如何创建类型为 point? 的东西
- documentation 似乎非常坚持我应该使用
AddGeometryColumn()
而不是直接将列添加到我的位置 table,但我不明白为什么以及是否会这样随着我的应用程序的增长成为一个问题。如果我需要做的只是找到两个地方(在二维平面上)之间的距离作为陆地旅行距离,这对我来说会有问题吗? - 如何将此结果转换为英里(可能还有公里)。我应该 运行 一起成为不同的查询吗?我对经纬度的理解让我认为返回的这个数字不会是英里的简单线性转换。
我建议使用
- 使用
geography(Point,4326
) 作为位置的数据类型 - 查询为
ST_Distance(location1::geography, location2::geography)
通过转换为 geography
数据类型,结果为 meters
,而不是度数,这将毫无意义。请注意,4326 与 WGS84 是同一系统(大多数 GPS 数据所参考的系统)
另请参阅此 Q/A 了解更多详情:
https://gis.stackexchange.com/questions/76967/what-is-the-unit-used-in-st-distance
编辑:
回复:AddGeometryColumn
不需要使用该功能,这只是一种方便 - 据我所知。
编辑:
补充说明,不是你问的,但postgis中也有空间索引类型:
CREATE INDEX loc_idx ON places USING gist (location);
- 是的,如果您使用的是 PostGIS,请不要使用
point
。 Point 是原生类型。 PostGIS 是一个扩展,可以做你想做的事。如果一切都在4326,你应该看看geography
类型并使用它。 - 切勿使用
AddGeometryColumn()
,除非您使用的是 PostGIS 1.x。 PostGIS 2.x 支持类型修饰符,您可以使用ALTER TABLE
代替。 - 要使用获取里程,只需 return 公里和
* 0.621371192
这有点奇怪,但很实用。
SELECT ST_Distance(
(SELECT location FROM places WHERE name = 'The Place of Luke'),
(SELECT location FROM places WHERE name = 'The Place of Bob')
);
通常您会在批量处理的 JOIN 中看到它,但它也可以按照您的预期在相关子查询中使用。
SELECT
l1.location,
l2.location,
ST_Distance( l1.location, l2.location )
FROM location AS l1
JOIN location AS l2
ON l2.location = 'The Place of Luke'
WHERE places = 'The Place of Bob';