PostGIS 核心函数手册
必记基础
- geometry:平面几何,单位度,不准
- geography:地球球面,单位米,真实距离
- 业务 99% 必须用 geography
一、空间对象创建(基础必学)
1. ST_MakePoint
作用:经纬度 → 数据库可识别的空间点
基础语法
ST_MakePoint(经度, 纬度)
示例
-- 创建北京中心点的空间点
SELECT ST_MakePoint(116.40, 39.90);
查询结果
POINT(116.40 39.90) 点对象业务场景
接收前端用户定位、商家坐标、设备 GPS,转换成 PostGIS 可计算的点。
使用注意事项
- 必须严格遵循「经度在前,纬度在后」的顺序,颠倒会导致坐标定位到海外;
- 生成的点无坐标系,仅能作为基础对象,需配合
ST_SetSRID绑定坐标系后才能参与空间计算; - 可通过
ST_X(geom)/ST_Y(geom)反向提取经纬度数值。
2. ST_SetSRID
作用:给空间对象绑定坐标系(核心为 4326)
基础语法
ST_SetSRID(几何对象, 坐标系编号)
示例
-- 给北京中心点绑定4326坐标系
SELECT ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326);
查询结果
带坐标系的点:
SRID=4326;POINT(116.40 39.90)业务场景
让坐标具备真实地理意义,用于距离、范围、包含关系计算。
使用注意事项
- 无 SRID 的空间对象无法进行有效地理计算,所有参与业务的空间对象必须绑定 SRID;
- 常用 SRID:4326(WGS84,用于距离 / 范围计算)、3857(墨卡托投影,用于前端地图展示);
- 批量修复无 SRID 数据时,需先通过
ST_SRID(geom)筛选出 SRID=0 的记录,避免重复绑定。
3. ST_GeomFromText
作用:WKT 文本 → 点 / 线 / 面对象
基础语法
ST_GeomFromText(WKT文本, 坐标系编号)
示例
-- 示例1:创建点
SELECT ST_GeomFromText('POINT(116.40 39.90)', 4326);
-- 示例2:创建北京到天津的路线
SELECT ST_GeomFromText('LINESTRING(116.40 39.90, 117.20 39.13)', 4326);
-- 示例3:创建简单的多边形区域
SELECT ST_GeomFromText('POLYGON((116.40 39.90, 116.50 39.90, 116.50 39.80, 116.40 39.90))', 4326);
查询结果
返回对应点、线、面空间对象。
业务场景
外部 GIS 数据导入、手动构造区域、接口参数解析。
使用注意事项
- WKT 文本中坐标必须用空格分隔,不可用逗号;
- 多边形需保证闭合(最后一个点与第一个点重合),否则会报错;
- 反向输出空间对象为 WKT 文本可使用
ST_AsText(geom),便于数据导出 / 前端展示。
4. ST_MakeLine
作用:多个点 → 一条线(轨迹 / 路线)
基础语法
-- 手动拼接
ST_MakeLine(点对象1, 点对象2, ...)
-- 从表中拼接
ST_MakeLine(geom ORDER BY 排序字段)
示例
-- 示例1:手动拼接北京到上海的路线
SELECT ST_MakeLine(
ST_MakePoint(116.40, 39.90),
ST_MakePoint(121.47, 31.23)
);
-- 示例2:从表中拼接用户GPS轨迹
SELECT ST_MakeLine(geom ORDER BY gps_time) AS track_line
FROM gps_data
WHERE user_id = '1001' AND gps_date = '2026-02-25';
查询结果
线对象
业务场景
用户 GPS 轨迹拼接、车辆行驶路线、公交 / 地铁线路、配送路径。
使用注意事项
- 从表中拼接时必须指定排序字段(如时间),否则路线会错乱;
- 需先过滤表中
geom IS NULL的记录,避免轨迹断裂; - 若存在重复 GPS 点,可通过
ST_MakeLine(DISTINCT geom ORDER BY ...)去重后再拼接。
二、空间关系判断(业务核心)
1. ST_DWithin(你最常用)
作用:查询 指定距离内 的所有数据
基础语法
ST_DWithin(空间对象A, 空间对象B, 距离阈值, use_spheroid=true)
示例
-- 示例1:查询北京中心点10公里内的乡镇
SELECT province, city, county, town
FROM gsyj_gsxzbj
WHERE ST_DWithin(
geom::geography,
ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography,
10000 -- 10公里(米)
);
-- 示例2:外卖场景-查询用户5公里内的商家
SELECT shop_name, address
FROM shop_info
WHERE ST_DWithin(
shop_geom::geography,
ST_SetSRID(ST_MakePoint(116.38, 39.92), 4326)::geography,
5000
);
查询结果
指定距离内的商家、网点、设备、乡镇列表。
业务场景
附近门店、外卖配送范围、就近派单、电子围栏、周边 POI 检索。
使用注意事项
- 必须将 geometry 类型转为 geography(
::geography),否则距离单位为 “度”,结果完全错误; - 距离阈值单位为米,需提前完成公里→米的转换(如 10 公里 = 10000 米);
- 大数据量查询前,必须给 geom 字段创建 GIST 空间索引(
CREATE INDEX idx_表名_geom ON 表名 USING GIST(geom);),否则查询极慢; use_spheroid=false可切换为球体计算,速度更快但精度略低,适合大范围低精度场景。
2. ST_Intersects
作用:判断两个空间对象是否相交 / 重叠
基础语法
ST_Intersects(空间对象A, 空间对象B)
示例
-- 示例1:判断长安街是否穿过朝阳区
SELECT ST_Intersects(
(SELECT geom FROM road_info WHERE road_name = '长安街'),
(SELECT geom FROM gsyj_gsxzbj WHERE county = '朝阳区' AND city = '北京市')
);
-- 示例2:查询洪水覆盖的农田
SELECT farm_id, farm_name
FROM farm_info
WHERE ST_Intersects(
farm_geom,
(SELECT flood_geom FROM flood_data WHERE flood_id = 'F001')
);
查询结果
true /false(单判断);符合条件的列表(范围查询)
业务场景
判断道路是否穿过行政区、洪水是否覆盖农田、线路是否穿越保护区。
使用注意事项
- 只要两个对象有任意一点重叠,即返回 true,需注意 “边界接触” 也判定为相交;
- 若需判断 “完全不相交”,可使用反向函数
ST_Disjoint(A,B); - 参与计算的两个对象需统一坐标系,否则可能出现误判。
3. ST_Contains
作用:判断 A 完全包含 B
基础语法
ST_Contains(包含方对象A, 被包含方对象B)
示例
-- 示例1:判断用户定位是否在海淀区内
SELECT ST_Contains(
(SELECT geom FROM gsyj_gsxzbj WHERE county = '海淀区' AND city = '北京市'),
ST_SetSRID(ST_MakePoint(116.30, 39.95), 4326)
);
-- 示例2:查询北京市下辖的所有乡镇
SELECT town
FROM gsyj_gsxzbj
WHERE ST_Contains(
(SELECT geom FROM gsyj_gsxzbj WHERE city = '北京市' AND county = ''),
geom
);
查询结果
true /false(单判断);符合条件的列表(范围查询)
业务场景
判断用户是否在某个城市 / 区内、商家是否在商圈内、点位是否在管控区内。
使用注意事项
- 严格遵循 “包含方在前,被包含方在后” 的参数顺序,颠倒会导致结果错误;
- 点落在对象 A 的边界上时,
ST_Contains返回 false,若需包含边界判断,需使用ST_Covers; - 可使用
ST_Within(B,A)替代(效果一致),参数顺序更符合 “B 是否在 A 内” 的日常逻辑。
4. ST_Covers
作用:宽松包含(边界上也算)
基础语法
ST_Covers(覆盖方对象A, 被覆盖方对象B)
示例
-- 示例1:判断基站是否归属朝阳区(含边界)
SELECT ST_Covers(
(SELECT geom FROM gsyj_gsxzbj WHERE county = '朝阳区'),
(SELECT geom FROM base_station WHERE base_id = 'B001')
);
-- 示例2:批量判断边界点位的行政区划归属
SELECT point_id, ST_Covers(area_geom, point_geom) AS is_cover
FROM boundary_points, area_info
WHERE area_info.area_name = '朝阳区';
查询结果
true / false
业务场景
基站归属、边界点位归属、卡口 / 围栏边界判断。
使用注意事项
- 参数顺序与
ST_Contains一致,覆盖方在前,被覆盖方在后; - 反向判断可使用
ST_CoveredBy(B,A),效果与ST_Covers(A,B)完全一致; - 实际业务中优先使用
ST_Covers,可避免边界点 “归属模糊” 导致的数据遗漏。
三、距离 / 长度 / 面积计算
1. ST_Distance
作用:计算两点 / 两对象的真实球面距离
基础语法
ST_Distance(空间对象A, 空间对象B)
示例
-- 示例1:计算北京到上海的距离(公里)
SELECT ST_Distance(
ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography,
ST_SetSRID(ST_MakePoint(121.47, 31.23), 4326)::geography
) / 1000 AS distance_km;
-- 示例2:按距离排序查询10公里内的乡镇
SELECT town, ROUND(ST_Distance(geom::geography, ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography)/1000,1) AS km
FROM gsyj_gsxzbj
WHERE ST_DWithin(geom::geography, ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography, 10000)
ORDER BY km ASC;
查询结果
距离数值(公里);带距离的列表
业务场景
用户到商家距离、两点车程参考、设备间距离、按距离排序。
使用注意事项
- 必须转为 geography 类型,否则计算的是平面距离(单位度),与真实球面距离偏差极大;
- 结果单位为米,需除以 1000 转为公里,可通过
ROUND(结果, 1)保留 1 位小数,提升可读性; - 支持点、线、面等任意空间对象的距离计算,返回的是两对象的最短距离。
2. ST_Length
作用:计算线对象长度
基础语法
ST_Length(线对象)
-- 示例1:计算北京到天津到上海路线的总里程
SELECT ST_Length(
ST_MakeLine(
ST_MakePoint(116.40, 39.90),
ST_MakePoint(117.20, 39.13),
ST_MakePoint(121.47, 31.23)
)::geography
) / 1000 AS line_length_km;
-- 示例2:查询北京公交1号线的里程
SELECT ST_Length(road_geom::geography)/1000 AS bus_line_km
FROM road_info
WHERE road_name = '北京公交1号线';
查询结果
线路里程数值(公里)
业务场景
GPS 轨迹总里程、道路里程、河流长度、配送路线长度。
使用注意事项
- 仅对线对象有效,传入点 / 面对象会返回 0;
- 转为 geography 类型后计算的是球面长度,未转换则为平面长度(单位度),无实际业务意义;
- 可使用
ST_LengthSpheroid(线对象, 椭球体参数)自定义椭球体,默认参数已满足绝大部分业务需求。
3. ST_Area
作用:计算面对象面积
基础语法
ST_Area(面对象)
示例
-- 示例1:计算朝阳区的面积(平方公里)
SELECT ST_Area(
(SELECT geom FROM gsyj_gsxzbj WHERE county = '朝阳区' AND city = '北京市')::geography
) / 1000000 AS area_km2;
-- 示例2:计算洪水覆盖的面积
SELECT ST_Area(flood_geom::geography)/1000000 AS flood_area_km2
FROM flood_data
WHERE flood_id = 'F001';
查询结果
面积数值(平方公里)
业务场景
行政区面积、受灾面积、农田面积、商圈覆盖面积。
使用注意事项
- 仅对面对象有效,传入点 / 线对象会返回 0;
- 转为 geography 类型后结果单位为平方米,需除以 1000000 转为平方公里(1 平方公里 = 1000000 平方米);
- 若需计算亩数,可除以 666.67(1 亩≈666.67 平方米);
ST_Area(geom::geography, true)中true表示使用椭球体计算,精度更高,默认即为 true。
4. ST_Distance_Sphere
作用:快速计算两点距离(性能优先)
基础语法
ST_Distance_Sphere(点对象A, 点对象B)
示例
-- 示例1:快速计算用户到商家的距离
SELECT shop_name, ROUND(ST_Distance_Sphere(
ST_MakePoint(116.38, 39.92),
shop_geom
)/1000,1) AS distance_km
FROM shop_info;
-- 示例2:批量计算设备到基站的距离(高性能)
SELECT device_id, ROUND(ST_Distance_Sphere(device_geom, base_geom)/1000,1) AS km
FROM device_info, base_station
WHERE base_station.base_id = 'B001';
查询结果
距离数值(公里)
业务场景
大批量商家列表、首页附近推荐、高并发简单距离展示。
使用注意事项
- 仅支持点对象,不支持线 / 面对象;
- 无需转为 geography 类型,直接传入点对象即可,计算速度比
ST_Distance快 30% 以上; - 精度略低于
ST_Distance(误差约 0.1%-0.5%),适合对精度要求不高的高并发场景; - 结果单位为米,需除以 1000 转为公里。
四、几何操作(进阶必备)
1. ST_Buffer
作用:生成缓冲圈 / 缓冲带
基础语法
ST_Buffer(空间对象, 缓冲距离, 精度参数)
示例
-- 示例1:生成北京中心点10公里缓冲圈(供前端展示)
SELECT ST_Buffer(
ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography,
10000
)::geometry AS buffer_geom;
-- 示例2:生成长安街50米缓冲带
SELECT ST_Buffer(road_geom::geography, 50)::geometry AS road_buffer
FROM road_info
WHERE road_name = '长安街';
查询结果
圆形 / 带状面对象
业务场景
地图画圈展示、电子围栏、道路影响范围、基站覆盖圈、禁入区扩边。
使用注意事项
- 缓冲距离单位为米,需先完成公里→米的转换;
- 点→圆、线→带状、面→外扩 / 内缩(距离为负数时内缩);
- 生成的 geography 类型缓冲圈需转为 geometry(
::geometry),否则前端地图无法正常渲染; - 精度参数
quad_segs=32可提升缓冲圈圆润度(默认 8),如ST_Buffer(geom, 10000, 'quad_segs=32')。
2. ST_Intersection
作用:取两个空间对象的重叠部分
基础语法
ST_Intersection(空间对象A, 空间对象B)
示例
-- 示例1:计算洪水覆盖的朝阳区面积
SELECT ST_Area(
ST_Intersection(
(SELECT flood_geom FROM flood_data WHERE flood_id = 'F001'),
(SELECT geom FROM gsyj_gsxzbj WHERE county = '朝阳区')
)::geography
)/1000000 AS flood_area_km2;
-- 示例2:提取两个商圈的重叠区域
SELECT ST_AsGeoJSON(ST_Intersection(
(SELECT geom FROM business_circle WHERE name = '王府井'),
(SELECT geom FROM business_circle WHERE name = '西单')
)) AS overlap_geom;
查询结果
重叠区域的面对象;重叠区域的面积 / GeoJSON
业务场景
洪水受灾区域、多区交叉商圈、规划重叠范围。
使用注意事项
- 两个对象无重叠时返回 NULL,需配合
COALESCE处理(如COALESCE(ST_Area(...), 0),无重叠时返回 0); - 可通过
ST_AsText/ST_AsGeoJSON输出重叠区域的文本 / JSON 格式,便于前端展示; - 支持点、线、面任意组合,返回的是重叠部分的几何对象(如点与面相交返回点,线与面相交返回线)。
3. ST_Union
作用:合并多个空间对象为一个
基础语法
-- 合并表中所有对象
ST_Union(空间对象)
-- 合并指定多个对象
ST_Union(对象A, 对象B)
示例
-- 示例1:合并北京市所有区县为一个整体面
SELECT ST_Union(geom) AS beijing_geom
FROM gsyj_gsxzbj
WHERE city = '北京市' AND county <> '';
-- 示例2:合并用户的多个农田地块并计算总面积
SELECT ST_Union(farm_geom) AS total_farm_geom,
ST_Area(ST_Union(farm_geom)::geography)/1000000 AS total_area_km2
FROM farm_info
WHERE user_id = '1001';
查询结果
合并后的大面对象;合并对象 + 总面积
业务场景
多区县合并为市、零散地块合并、多区域统一统计。
使用注意事项
- 按分组合并时需配合
GROUP BY(如SELECT city, ST_Union(geom) FROM 表 GROUP BY city); - 合并时会自动去重、融合重叠边界,无需手动处理重复区域;
- 大数据量合并前需创建空间索引,提升合并速度;
- 支持点、线、面合并,点合并返回多点对象,线合并返回多线对象,面合并返回多面 / 单面对象。
4. ST_Centroid
作用:计算面 / 线对象的中心点
基础语法
ST_Centroid(空间对象)
示例
-- 示例1:计算朝阳区的中心点经纬度
SELECT
ST_X(ST_Centroid(geom)) AS lon,
ST_Y(ST_Centroid(geom)) AS lat
FROM gsyj_gsxzbj
WHERE county = '朝阳区' AND city = '北京市';
-- 示例2:计算公交线路的中点
SELECT ST_Centroid(road_geom) AS line_center
FROM road_info
WHERE road_name = '北京公交1号线';
查询结果
中心点坐标;中心点对象
业务场景
区域名称标注、城市中心点、不规则区域中心定位。
使用注意事项
- 面对象返回质心,线对象返回长度中点,点对象返回自身;
- 质心可能落在面外部(如不规则凹面),需保证点在面内时,改用
ST_PointOnSurface; - 可通过
ROUND(ST_X(...), 6)保留 6 位小数(经纬度 6 位小数≈1 米精度)。
五、坐标系与前端输出
ST_Transform
作用:坐标系转换
基础语法
ST_Transform(空间对象, 目标坐标系编号)
示例
-- 示例1:4326转3857(供前端地图展示)
SELECT ST_Transform(
ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326),
3857
);
-- 示例2:批量转换表中geom的坐标系
UPDATE gsyj_gsxzbj
SET geom = ST_Transform(geom, 3857)
WHERE ST_SRID(geom) = 4326;
查询结果
转换后的空间对象;无返回(批量更新)
业务场景
后端计算(4326)→ 前端地图展示(3857)
使用注意事项
- 转换前需通过
ST_SRID(geom)确认原坐标系,避免重复转换导致精度丢失; - 常用转换场景:4326→3857(展示)、3857→4326(前端坐标转后端计算)、4326→4490(国内项目);
- 转换后需验证:
SELECT ST_SRID(ST_Transform(geom, 3857)) FROM 表 LIMIT 1;,确保转换成功。
ST_AsGeoJSON
作用:转前端地图可直接渲染的 JSON
基础语法
ST_AsGeoJSON(空间对象)
示例
-- 示例1:将10公里缓冲圈转为GeoJSON
SELECT ST_AsGeoJSON(
ST_Buffer(ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography, 10000)::geometry
) AS buffer_geojson;
-- 示例2:批量导出区域的GeoJSON供前端渲染
SELECT area_name, ST_AsGeoJSON(geom) AS area_geojson
FROM gsyj_gsxzbj
WHERE city = '北京市';
查询结果
标准 GeoJSON 字符串
业务场景
高德 / 百度 / Leaflet 地图渲染区域、路线、点位。
使用注意事项
- 需将 geography 类型转为 geometry 后再转换,否则可能出现格式兼容问题;
- 可通过
ST_AsGeoJSON(geom, 6)指定坐标小数位数(6 位),减少数据体积; - GeoJSON 是前端 GIS 框架通用格式,无需二次解析可直接渲染。
六、高频实战扩展(必学)
ST_PointOnSurface
作用:获取面内部一定存在的点
基础语法
ST_PointOnSurface(面对象)
示例
-- 示例:获取朝阳区内部的点(用于地图标注)
SELECT ST_AsText(ST_PointOnSurface(geom)) AS inner_point
FROM gsyj_gsxzbj
WHERE county = '朝阳区' AND city = '北京市';
查询结果
面内的点对象
业务场景
行政区划标注、区域文本展示,不会飘到区域外。
使用注意事项
- 仅对面对象有效,线 / 点对象返回自身;
- 保证返回的点一定在面内部,解决
ST_Centroid质心可能在面外的问题; - 可配合
ST_X/ST_Y提取坐标,用于地图标注的位置定位。
ST_Simplify
作用:简化几何,减少坐标点
基础语法
ST_Simplify(空间对象, 容差)
示例
-- 示例:简化朝阳区geom,提升前端渲染速度
SELECT ST_Simplify(geom, 0.001) AS simplified_geom
FROM gsyj_gsxzbj
WHERE county = '朝阳区';
查询结果
简化后的空间对象
业务场景
前端地图加速、大数据量传输优化。
使用注意事项
- 容差单位为度(4326 坐标系),0.001 度≈111 米,容差越大简化越彻底;
- 简化仅减少坐标点数量,不改变对象整体形状,适合前端低精度展示;
- 简化后的数据不可用于高精度计算,仅用于可视化。
ST_Within
作用:判断点是否在面内(参数更直观)
基础语法
ST_Within(被包含方对象B, 包含方对象A)
示例
-- 示例1:判断用户定位是否在北京市内
SELECT ST_Within(
ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326),
(SELECT geom FROM gsyj_gsxzbj WHERE city = '北京市' AND county = '')
);
-- 示例2:查询在电子围栏内的设备
SELECT device_id
FROM device_info
WHERE ST_Within(device_geom, (SELECT fence_geom FROM fence_info WHERE fence_id = 'F001'));
查询结果
true /false;符合条件的设备列表
业务场景
电子围栏、用户归属地、入区告警。
使用注意事项
- 参数顺序为 “被包含方在前,包含方在后”,与
ST_Contains相反,更符合日常逻辑; - 点在边界上时返回 false,需包含边界时改用
ST_CoveredBy(B,A); - 大数据量查询时,需给包含方对象创建空间索引,提升查询效率。
七、企业级万能模板(直接复制)
-- 模板:范围查询+距离排序+分页
SELECT
id,
name,
ROUND(ST_Distance(geom::geography, ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography)/1000, 1) AS distance_km
FROM gsyj_gsxzbj
WHERE
geom IS NOT NULL
AND ST_DWithin(
geom::geography,
ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography,
10000
)
ORDER BY distance_km ASC
LIMIT 10 OFFSET 0;
八、新手必避 4 大错误
- 不加
::geography→ 距离计算单位为 “度”,结果完全错误; - 不建 GIST 索引 → 百万级数据查询从秒级变为分钟级,无法满足业务性能要求;
- 经纬度写反 → 坐标定位到海外,所有空间计算结果无意义;
- 坐标系不统一 → 出现对象偏移、相交误判、距离算不准等问题。
总结
- 所有空间计算的核心前提是绑定 4326 坐标系 + 转 geography 类型,这是避免结果错误的关键;
- 高频核心函数需牢记基础语法 + 使用注意事项:
ST_DWithin(范围筛选)、ST_Distance(距离计算)、ST_Buffer(范围生成)、ST_AsGeoJSON(前端输出)、ST_Contains(判包含) - 性能优化关键:给 geom 字段创建 GIST 空间索引,大数据量场景优先用
ST_Distance_Sphere提升查询速度,前端展示前用ST_Simplify简化几何对象。 - 结果类型区分:
- 布尔型:
ST_Intersects/ST_Contains/ST_Covers; - 数值型:
ST_Distance/ST_Length/ST_Area; - 空间对象型:
ST_MakePoint/ST_Buffer/ST_Union/ST_Centroid; - 列表型:范围筛选类函数(
ST_DWithin/ST_Intersects)。
- 布尔型:
- 单位转换:geography 类型用米,转公里除以 1000,转平方公里除以 1000000。
浙公网安备 33010602011771号