PostgreSQL:在距离内找到记录

时间:2015-03-31 19:26:47

标签: ruby-on-rails postgresql postgis

对于我的应用程序,我是一个用户,其中每个人都是地理定位的。我想要实现的是检索距离较远的用户(例如,距离> = 1000且距离< = 2000的用户)。

我的用户有一个longitude和一个latitude字段。

到目前为止,这是我的要求:

select(%{users.*,
  ST_DISTANCE(
    ST_GeographyFromText(
      'SRID=4326;POINT(' || users.longitude || ' ' || users.latitude || ')'
    ),
    ST_GeographyFromText('SRID=4326;POINT(%f %f)')
  ) as distance
} % [longitude, latitude])
.where(%{
  ST_DISTANCE(
    ST_GeographyFromText(
      'SRID=4326;POINT(' || users.longitude || ' ' || users.latitude || ')'
    ),
    ST_GeographyFromText('SRID=4326;POINT(%f %f)')
  ) > %d AND
  ST_DWithin(
    ST_GeographyFromText(
      'SRID=4326;POINT(' || users.longitude || ' ' || users.latitude || ')'
    ),
    ST_GeographyFromText('SRID=4326;POINT(%f %f)'),
    %d
  )
} % [longitude, latitude, 15, longitude, latitude, distance_in_meters])

这非常难看:你能帮助我吗?

1 个答案:

答案 0 :(得分:1)

您应该将数据存储为具有空间索引的新geog列:

ALTER TABLE users ADD COLUMN geog geography(Point, 4326);
UPDATE users SET geog = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326);
CREATE INDEX users_geog_idx ON users USING gist (geog);

您可能还想删除经度和纬度列,因为它们是多余的。可以使用ST_X和ST_Y从点几何获得坐标。


要查找指定范围内的记录,请使用常规SELECT语句捕获外部距离,然后使用EXCEPT删除内部距离。

WITH poi AS (
  SELECT ST_SetSRID(ST_MakePoint(%longitude, %latitude), 4326)::geography AS poi
)
SELECT users.*, ST_Distance(geog, poi) AS distance
FROM users
JOIN poi ON ST_DWithin(geog, poi, %outer_dist)
EXCEPT SELECT users.*, ST_Distance(geog, poi) AS distance
FROM users
JOIN poi ON ST_DWithin(geog, poi, %inner_dist);

参数标有%,您可以根据应用重新格式化。