对于我的应用程序,我是一个用户,其中每个人都是地理定位的。我想要实现的是检索距离较远的用户(例如,距离> = 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])
这非常难看:你能帮助我吗?
答案 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);
参数标有%
,您可以根据应用重新格式化。