在PostgreSQL中按纬度和经度查找最近的位置

问题描述 投票:6回答:4

嗨,我正在尝试通过Postgresql数据库中的纬度和经度查找最近的位置。但是当我运行以下查询时,它显示的列距离不存在。

ERROR:  column "distance" does not exist
LINE 1: ... ) ) ) AS distance FROM station_location   HAVING distance <...
                                                             ^
********** Error **********

ERROR: column "distance" does not exist
SQL state: 42703
Character: 218

CREATE TABLE station_location
(
  id bigint NOT NULL DEFAULT nextval('location_id_seq'::regclass),
  state_name character varying NOT NULL,
  country_name character varying NOT NULL,
  locality character varying NOT NULL,
  created_date timestamp without time zone NOT NULL,
  is_delete boolean NOT NULL DEFAULT false,
  lat double precision,
  lng double precision,
  CONSTRAINT location_pkey PRIMARY KEY (id)
)

SELECT  *,( 3959 * acos( cos( radians(6.414478) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(12.466646) ) + sin( radians(6.414478) ) * sin( radians( lat ) ) ) ) AS distance 
FROM station_location
HAVING distance < 5
ORDER BY distance
LIMIT 20;
sql postgresql spatial
4个回答
2
投票
select * from (
SELECT  *,( 3959 * acos( cos( radians(6.414478) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(12.466646) ) + sin( radians(6.414478) ) * sin( radians( lat ) ) ) ) AS distance 
FROM station_location
) al
where distance < 5
ORDER BY distance
LIMIT 20;

13
投票

PostGIS

不要在这样的桌子上长期存放经纬度。而是使用PostGIS几何图形或geography type

CREATE EXTENSION postgis;

CREATE TABLE foo (
  geog geography;
);

CREATE INDEX ON foo USING gist(geog);

INSERT INTO foo (geog)
  VALUES (ST_MakePoint(x,y));

现在,当您需要查询它时,您可以使用KNN (<->)实际在索引上执行此操作。

<->

在查询中,您明确拥有SELECT * FROM foo ORDER BY foo.geog <-> ST_MakePoint(x,y)::geography; 。您也可以在索引上执行此操作。

HAVING distance < 5

如果所有点都位于SELECT * FROM foo WHERE ST_DWithin(foo.geog, ST_MakePoint(x,y)::geography, distance_in_meters) ORDER BY foo.geog <-> ST_MakePoint(x,y)::geography; 之外,这将确保不返回任何内容。

此外,x和y是十进制数字distance_in_meters


1
投票

请参见ST_MakePoint(46.06, 14.505),您将找到如何在this gist类型上声明DOMAIN,以及如何重写point运算符以返回矫正距离。

声明从distance继承的latlong类型:

point

以公里为单位的矫正距离(在具有地球半径的球面上的距离:]

CREATE DOMAIN latlong AS point CHECK (VALUE[0] BETWEEN -90.0 AND 90.0 AND VALUE[1] BETWEEN -180 AND 180);

与拉特隆一起使用时,请使用此功能覆盖距离运算符CREATE OR REPLACE FUNCTION orthodromic_distance(latlong, latlong) RETURNS float AS $_$ SELECT acos( sin(radians($1[0])) * sin(radians($2[0])) + cos(radians($1[0])) * cos(radians($2[0])) * cos(radians($2[1]) - radians($1[1])) ) * 6370.0; $_$ LANGUAGE sql IMMUTABLE;

<->

现在在您的SQL查询中,找到最近的实体:

CREATE OPERATOR <-> ( PROCEDURE = orthodromic_distance
, LEFTARG = latlong, RIGHTARG = latlong
);

您可能想使用latlong类型将位置WITH station_distance AS ( SELECT id AS station_id, point(lat, long)::latlong <-> point(6.414478, 12.466646)::latlong AS distance FROM station_location WHERE NOT is_deleted ) SELECT sl.state_name, sl.country_name, sl.locality, point(sl.lat, sl.long)::latlong AS coordinates, sd.distance FROM station_location sl JOIN station_distance sd ON sd.station_id = sl.id ORDER BY distance ASC LIMIT 10 lat存储在同一字段中。


0
投票

手册阐明:

输出列的名称可以用来引用列中的值ORDER BY和GROUP BY子句,但不在WHERE或HAVING子句中;在那里,您必须改写表达式。

© www.soinside.com 2019 - 2024. All rights reserved.