PostGIS常用函数有哪些?ST_Buffer怎么写?
PostGIS常用函数有哪些?ST_Buffer怎么写? 这是很多刚从桌面 GIS 转到空间数据库的同学会遇到的问题:知道 PostGIS 很强,但打开 SQL 编辑器后,不清楚哪些函数最常用,也不知道缓冲区分析的 SQL 应该怎样写才算正确。
本文以实际 GIS 工作流为主线,整理 PostGIS 中最常用的一组空间函数,并重点讲清楚 ST_Buffer 的基本写法、单位问题、投影要求、常见错误和结果检查方法。适合 GIS 学生、初级 GIS 工程师、空间数据分析人员和正在学习 PostgreSQL/PostGIS 的读者。

引言:先把 PostGIS常用函数 分成几类
学习 PostGIS 不建议从函数大全开始背。更实用的方法是按 GIS 工作流分类:先看数据是什么,再判断空间关系,然后做分析,最后输出结果。
常见工作中,PostGIS 常用函数大致可以分为以下几类:
- 几何信息函数:查看几何类型、坐标系、边界范围。
- 几何构造函数:从 WKT、经纬度、GeoJSON 等创建几何对象。
- 空间关系函数:判断相交、包含、距离内、相离等关系。
- 空间分析函数:缓冲区、叠加、裁剪、合并、差集等。
- 测量函数:计算长度、面积、距离。
- 坐标转换函数:处理不同坐标系之间的转换。
- 输出转换函数:把结果转成 WKT、GeoJSON、MVT 等格式。
其中 ST_Buffer 属于空间分析函数,常用于道路影响范围、点位服务半径、河流保护带、建筑退让线、管线安全距离等分析场景。
背景:为什么 ST_Buffer 写错后结果经常不对
很多人第一次写 ST_Buffer 时,会直接使用下面这种 SQL:
SELECT ST_Buffer(geom, 100)
FROM roads;
这条语句语法上可能没有问题,但结果是否正确,取决于 geom 的坐标系单位。如果数据是投影坐标系,单位通常是米,那么 100 大概率表示 100 米;如果数据是经纬度坐标系,单位是度,那么 100 就不是 100 米,而是 100 度,结果会非常夸张。
所以,写 ST_Buffer 前必须先确认三件事:
- 空间字段是不是有效几何。
- SRID 是否正确设置。
- 坐标系单位是否适合直接做距离分析。
可以先用下面的 SQL 检查表中的几何类型和 SRID:
SELECT
GeometryType(geom) AS geom_type,
ST_SRID(geom) AS srid,
COUNT(*) AS feature_count
FROM roads
GROUP BY GeometryType(geom), ST_SRID(geom);
如果返回的 SRID 是 4326,通常表示 WGS 84 经纬度坐标。此时不建议直接使用 ST_Buffer(geom, 100) 来表达 100 米缓冲区。
原理:PostGIS常用函数 的基本逻辑
PostGIS 的核心对象是几何字段,常见字段名为 geom。多数 PostGIS 常用函数都遵循类似结构:
函数名(几何字段或几何对象, 参数)
例如:
| 用途 | 常用函数 | 说明 |
|---|---|---|
| 查看坐标系 | ST_SRID(geom) |
返回几何对象的 SRID |
| 坐标转换 | ST_Transform(geom, 目标SRID) |
把几何转换到另一个坐标系 |
| 空间相交 | ST_Intersects(a.geom, b.geom) |
判断两个几何是否相交 |
| 距离内查询 | ST_DWithin(a.geom, b.geom, 距离) |
判断两个几何是否在指定距离内 |
| 缓冲区 | ST_Buffer(geom, 距离) |
生成指定距离的缓冲区面 |
| 面积计算 | ST_Area(geom) |
计算面几何面积 |
| 长度计算 | ST_Length(geom) |
计算线几何长度 |
| 结果输出 | ST_AsGeoJSON(geom) |
输出 GeoJSON 字符串 |
ST_Buffer 的原理是:以点、线或面为输入,根据指定距离向外或向内生成一个新的面几何。点缓冲区通常是圆形,线缓冲区是沿线两侧扩展的面,面缓冲区可以向外扩张,也可以用负值向内收缩。
但要注意:PostGIS 中的 geometry 类型按坐标单位计算距离。坐标单位是度,缓冲距离就是度;坐标单位是米,缓冲距离才是米。
步骤:ST_Buffer怎么写 才适合实际项目
步骤一:确认空间表和字段
假设有一张道路表 roads,主键为 id,道路名称字段为 name,空间字段为 geom。
先检查表结构和空间字段情况:
SELECT
id,
name,
ST_GeometryType(geom) AS geom_type,
ST_SRID(geom) AS srid
FROM roads
LIMIT 10;
如果 geom_type 返回 ST_LineString 或 ST_MultiLineString,说明道路数据适合做线缓冲区。
步骤二:投影坐标系下直接写 ST_Buffer
如果道路数据已经是以米为单位的投影坐标系,例如某个城市使用的高斯克吕格、UTM 或地方投影坐标系,可以直接写:
SELECT
id,
name,
ST_Buffer(geom, 100) AS geom
FROM roads;
这表示为每条道路生成 100 米缓冲区。结果字段仍然命名为 geom,便于 QGIS、ArcGIS Pro 或 WebGIS 端直接识别为空间结果。
如果希望保存为新表:
CREATE TABLE road_buffer_100m AS
SELECT
id,
name,
ST_Buffer(geom, 100) AS geom
FROM roads;
创建新表后,建议补充空间索引:
CREATE INDEX road_buffer_100m_geom_idx
ON road_buffer_100m
USING GIST (geom);
步骤三:经纬度数据先转换坐标系再缓冲
如果原始数据是 EPSG:4326 经纬度坐标,不要直接用 ST_Buffer(geom, 100) 表示 100 米。更稳妥的做法是先用 ST_Transform 转到合适的投影坐标系,再做 ST_Buffer。
例如数据位于 UTM 50N 区域,可转换到 EPSG:32650:
SELECT
id,
name,
ST_Transform(
ST_Buffer(
ST_Transform(geom, 32650),
100
),
4326
) AS geom
FROM roads;
这段 SQL 的含义是:
- 先把
geom从 EPSG:4326 转到 EPSG:32650。 - 在以米为单位的投影坐标系中生成 100 米缓冲区。
- 再把缓冲区结果转回 EPSG:4326,便于 WebGIS 或通用地图服务使用。
如果你的项目区域不在 EPSG:32650,需要根据实际位置选择合适的投影坐标系。不要机械照抄 SRID。
步骤四:控制 ST_Buffer 的圆滑程度和端点样式
ST_Buffer 可以带第三个参数,用来控制缓冲区样式。例如:
SELECT
id,
name,
ST_Buffer(
geom,
100,
'quad_segs=8 endcap=round join=round'
) AS geom
FROM roads;
常见参数包括:
| 参数 | 示例 | 作用 |
|---|---|---|
quad_segs |
quad_segs=8 |
控制圆弧平滑程度,值越大越圆滑,几何也越复杂 |
endcap |
endcap=round |
控制线缓冲区端点样式 |
join |
join=round |
控制折线拐角连接样式 |
side |
side=left |
生成线的一侧缓冲区 |
例如只生成道路左侧 50 米缓冲区:
SELECT
id,
name,
ST_Buffer(
geom,
50,
'side=left endcap=flat join=round'
) AS geom
FROM roads;
这类写法常用于道路红线、河道一侧保护范围、管线影响范围等业务场景。
步骤五:用 ST_Buffer 配合空间查询
ST_Buffer 经常和 ST_Intersects 搭配使用。例如查询距离道路 100 米范围内的学校:
SELECT DISTINCT
s.id,
s.name,
s.geom
FROM schools s
JOIN roads r
ON ST_Intersects(
s.geom,
ST_Buffer(r.geom, 100)
);
如果数据量较大,更推荐使用 ST_DWithin,它通常更适合做距离范围查询,并且更容易利用空间索引:
SELECT DISTINCT
s.id,
s.name,
s.geom
FROM schools s
JOIN roads r
ON ST_DWithin(s.geom, r.geom, 100);
简单理解:如果只是判断“是否在 100 米范围内”,优先考虑 ST_DWithin;如果确实需要生成一个缓冲区面图层,再使用 ST_Buffer。
常见坑:PostGIS ST_Buffer 最容易出错的地方
坑一:把经纬度的度当成米
这是 ST_Buffer 最常见的问题。EPSG:4326 下的坐标单位是度,不是米。直接写 ST_Buffer(geom, 100) 会得到非常大的缓冲区。
正确思路是:先转换到合适的投影坐标系,再缓冲,必要时再转回经纬度。
坑二:SRID 为空或设置错误
如果 ST_SRID(geom) 返回 0,说明几何没有明确坐标系。此时不能盲目使用 ST_Transform,因为 PostGIS 不知道它原来属于哪个坐标系。
如果你确认数据本身就是 EPSG:4326,但只是缺少 SRID,可以使用:
UPDATE roads
SET geom = ST_SetSRID(geom, 4326)
WHERE ST_SRID(geom) = 0;
注意:ST_SetSRID 只是声明坐标系,不会改变坐标值;ST_Transform 才会真正转换坐标。
坑三:缓冲区结果几何太复杂
quad_segs 设置过大,会让缓冲区边界非常平滑,但也会导致节点数量增加,查询和渲染变慢。WebGIS 展示时尤其明显。
如果只是用于范围筛选,不一定要生成非常圆滑的缓冲区。可以适当降低 quad_segs:
SELECT
id,
ST_Buffer(geom, 100, 'quad_segs=4') AS geom
FROM roads;
坑四:对无效几何直接做缓冲
如果输入几何存在自相交、空几何或拓扑异常,ST_Buffer 可能报错,也可能生成意外结果。可以先检查几何有效性:
SELECT
id,
ST_IsValid(geom) AS is_valid,
ST_IsValidReason(geom) AS reason
FROM parcels
WHERE NOT ST_IsValid(geom);
必要时可以使用 ST_MakeValid 修复:
SELECT
id,
ST_Buffer(ST_MakeValid(geom), 10) AS geom
FROM parcels;
坑五:负缓冲导致面消失
对面数据使用负值缓冲可以实现向内收缩:
SELECT
id,
ST_Buffer(geom, -5) AS geom
FROM parcels;
但如果面很窄或面积很小,向内收缩后可能变成空几何。建议加上空几何过滤:
SELECT
id,
buf.geom
FROM (
SELECT
id,
ST_Buffer(geom, -5) AS geom
FROM parcels
) AS buf
WHERE NOT ST_IsEmpty(buf.geom);
方法比较:ST_Buffer、ST_DWithin、ST_Intersects 该怎么选
PostGIS 常用函数之间不是互相替代的关系,而是适用于不同目的。下面这个表可以帮助你快速判断。
| 需求 | 推荐函数 | 原因 |
|---|---|---|
| 生成可视化缓冲区图层 | ST_Buffer |
可以得到真实的面几何,适合制图和输出 |
| 查询某对象距离另一对象多少米以内 | ST_DWithin |
更适合范围判断,通常性能更好 |
| 判断两个图层是否相交 | ST_Intersects |
适合叠加筛选、点落区、线面相交判断 |
| 计算两个对象实际距离 | ST_Distance |
返回距离数值,可用于排序和统计 |
| 裁剪一个图层到另一个范围内 | ST_Intersection |
返回重叠部分的新几何 |
| 合并多个缓冲区 | ST_Union |
适合生成整体影响范围 |
例如,如果要生成“地铁站 800 米服务范围图”,可以用 ST_Buffer;如果只是要找出 800 米范围内的小区,优先使用 ST_DWithin;如果要输出服务范围和行政区的重叠区域,则可能需要 ST_Intersection。
检查清单:写 PostGIS ST_Buffer 前后要确认什么
在实际项目中,建议按下面清单检查,能避免大多数 ST_Buffer 结果异常问题。
- 检查 SRID:使用
ST_SRID(geom)确认坐标系是否正确。 - 确认单位:投影坐标系通常按米计算,经纬度坐标系通常按度计算。
- 选择投影:跨城市、跨省或跨国家数据,不要随意使用一个局部投影。
- 检查几何有效性:使用
ST_IsValid排查异常几何。 - 控制复杂度:合理设置
quad_segs,避免结果过重。 - 建立空间索引:对大表的空间字段创建 GiST 索引。
- 区分分析和查询:需要面结果用 ST_Buffer,只做距离筛选优先用 ST_DWithin。
- 验证结果:把结果加载到 QGIS 或 ArcGIS Pro 中抽查范围是否符合预期。
常用空间索引写法如下:
CREATE INDEX roads_geom_idx
ON roads
USING GIST (geom);
如果表数据更新较多,可以执行统计信息更新:
ANALYZE roads;
FAQ:PostGIS常用函数有哪些?ST_Buffer怎么写?
1. PostGIS 常用函数需要全部记住吗?
不需要。初学阶段建议先掌握 ST_SRID、ST_Transform、ST_Intersects、ST_DWithin、ST_Buffer、ST_Area、ST_Length、ST_AsGeoJSON 这几类函数。它们已经能覆盖大量日常 GIS 数据处理任务。
2. ST_Buffer 的距离单位是什么?
对于 geometry 类型,ST_Buffer 的距离单位取决于数据坐标系单位。投影坐标系如果单位是米,缓冲距离就是米;EPSG:4326 经纬度坐标系下,单位是度,不是米。
3. 经纬度数据能不能直接做 ST_Buffer?
技术上可以执行,但通常不适合表达米级缓冲区。实际项目中应先用 ST_Transform 转换到合适的投影坐标系,再执行 ST_Buffer。
4. ST_Buffer 和 ST_DWithin 有什么区别?
ST_Buffer 会生成一个新的面几何,适合制图和输出缓冲区结果。ST_DWithin 用于判断两个几何是否在指定距离内,适合空间查询和筛选。如果不需要真正输出缓冲区面,优先考虑 ST_DWithin。
5. 为什么 ST_Buffer 之后地图加载变慢?
缓冲区会增加几何节点数量,尤其是线数据和大范围面数据。可以降低 quad_segs,简化结果,或者只在服务端做范围判断,不把复杂缓冲区直接传到前端。
6. ST_Buffer 可以做内缓冲吗?
可以。对面几何使用负距离即可,例如 ST_Buffer(geom, -10) 表示向内收缩 10 个坐标单位。但如果面太小,结果可能为空,需要使用 ST_IsEmpty 检查。
7. ST_Buffer 生成的结果如何保存为新图层?
可以使用 CREATE TABLE AS SELECT 创建新表,再为结果表建立 GiST 空间索引。之后可在 QGIS、ArcGIS Pro 或 GeoServer 中直接加载这张结果表。
结论:先理解单位,再写 ST_Buffer
PostGIS常用函数有哪些?ST_Buffer怎么写? 这个问题的关键不在于背多少函数,而在于理解空间数据库的基本分析逻辑。日常工作中,先掌握坐标检查、坐标转换、空间关系判断、缓冲区分析和结果输出,就能解决大部分 PostGIS 入门到进阶场景。
写 ST_Buffer 时请记住一个原则:先确认坐标系和单位,再决定缓冲距离。如果是经纬度数据,通常要先转换到合适的投影坐标系;如果只是做距离范围查询,不一定要生成缓冲区,使用 ST_DWithin 往往更直接。
把这些 PostGIS 常用函数组合起来,你就可以在数据库中完成道路影响范围、设施服务半径、点线面空间筛选、面积长度统计等常见 GIS 分析任务,而不必每一步都依赖桌面软件手工处理。