PostGIS SQL查询示例:筛选A表中位于B表半径范围内的行
PostGIS 查询示例:筛选表A中位于表B半径范围内的行
基础查询语句
假设表A、B的经纬度采用WGS84坐标系(EPSG:4326,绝大多数GPS/地图数据的标准),且表B的radius单位为米,可以用以下查询:
SELECT DISTINCT a.* FROM 表A a JOIN 表B b ON ST_DWithin( -- 将表A的经纬度转为地理类型(用于球面距离计算) ST_SetSRID(ST_MakePoint(a.longitude, a.latitude), 4326)::geography, -- 将表B的经纬度转为地理类型 ST_SetSRID(ST_MakePoint(b.longitude, b.latitude), 4326)::geography, -- 表B的半径(单位:米) b.radius );
关键说明
ST_MakePoint(longitude, latitude):PostGIS中点的坐标顺序是经度在前,纬度在后,不要搞反::geography:转换为地理类型后,ST_DWithin会基于球面计算真实地表距离,比平面几何计算更符合实际场景DISTINCT:避免表A的同一行被表B中多个符合条件的条目重复返回
优化与简化
- 空间索引(大数据量必加)
如果表A或B的数据量较大,创建空间索引能大幅提升查询速度:
-- 给表A创建空间索引 CREATE INDEX idx_a_geography ON 表A USING GIST (ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)::geography); -- 给表B创建空间索引 CREATE INDEX idx_b_geography ON 表B USING GIST (ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)::geography);
- 利用表B已有的
point字段
如果表B的point字段已经是PostGIS空间类型(geometry或geography),可以直接替换构造点的语句,简化查询:
SELECT DISTINCT a.* FROM 表A a JOIN 表B b ON ST_DWithin( ST_SetSRID(ST_MakePoint(a.longitude, a.latitude), 4326)::geography, b.point::geography, b.radius );
注意事项
- 如果表B的
radius单位是千米,记得乘以1000转换成米 - 如果必须使用平面几何计算(比如特定投影坐标系),去掉
::geography转换,确保ST_SetSRID指定对应的平面坐标系EPSG代码
内容的提问来源于stack exchange,提问作者Čamo
相关产品推荐
相关产品推荐

