一、PostgreSQL常用操作:
1.创建数据库:
sql
-- 创建名为gis_db数据库
CREATE DATABASE gis_db;
2.连接到数据库:
bash
# 操作系统 shell 中
psql -d gis_db -U postgres
3.创建表:
sql
-- 创建一个存储小区信息的表,包含空间字段 geom(多边形,SRID 4326)
CREATE TABLE residential_zones (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
geom GEOMETRY(Polygon, 4326)
);
3.1 基础几何类型(OGC 标准)
| 类型 | 说明 |
|---|---|
Point |
点 |
LineString |
线(由多个点连接而成) |
Polygon |
多边形(由外环和零或多个内环组成) |
MultiPoint |
多点集合 |
MultiLineString |
多线集合 |
MultiPolygon |
多多边形集合 |
GeometryCollection |
混合几何集合(可包含上述任意类型) |
3.2 曲面类型(PostGIS 扩展 / SQL-MM 标准)
| 类型 | 说明 |
|---|---|
CircularString |
由圆弧段组成的线 |
CompoundCurve |
由直线段和圆弧段混合组成的线 |
CurvePolygon |
由曲线(含圆弧)构成边界的多边形 |
MultiCurve |
多曲线集合 |
MultiSurface |
多曲面集合 |
3.3 带 Z(高程)或 M(测量值)的变体
上述所有类型都可以带 Z(三维)、M(测量值)或 ZM(两者都有),例如:
-
PointZ -
LineStringM -
PolygonZM
在创建表时,也可直接使用 GEOMETRY(PointZ, 4326) 这样的约束。(只需将 Polygon 替换成其他几何类型名称即可)
4.插入数据:
sql
-- 插入一个多边形(小区边界),坐标顺序必须闭合(首尾相同)
INSERT INTO residential_zones (name, geom)
VALUES (
'东方花园',
ST_GeomFromText('POLYGON((116.40 39.90, 116.41 39.90, 116.41 39.91, 116.40 39.91, 116.40 39.90))', 4326)
);
5.查询数据:
sql
-- 查询所有小区
SELECT * FROM residential_zones;
-- 查询 id 为 1 的小区名称和几何对象
SELECT name, ST_AsText(geom) FROM residential_zones WHERE id = 1;
6.更新数据:
sql
-- 将 id 为 1 的小区名称改为"东方花园(一期)"
UPDATE residential_zones SET name = '东方花园(一期)' WHERE id = 1;
-- 查询所有小区
SELECT * FROM residential_zones;
7.删除数据:
sql
-- 删除 id 为 2 的小区记录
DELETE FROM residential_zones WHERE id = 2;
8.创建索引:
sql
-- 为 geom 字段创建 GIST 空间索引(强烈推荐,提升空间查询性能)
CREATE INDEX idx_residential_zones_geom ON residential_zones USING GIST (geom);
9.执行事务:
sql
-- 开启事务,连续执行两条更新,若出错则全部回滚
BEGIN;
UPDATE residential_zones SET name = 'A区' WHERE id = 1;
UPDATE residential_zones SET name = 'B区' WHERE id = 2;
COMMIT; -- 提交事务
-- 若要回滚,使用 ROLLBACK;
10.添加PostGIS扩展:
sql
-- 在数据库中启用 PostGIS 扩展(只需执行一次)
CREATE EXTENSION IF NOT EXISTS postgis;
二、PostGIS常用的空间查询语句
1.查询包含在指定几何对象内部的所有要素:
sql
-- 查询完全位于某个大矩形内部的小区
SELECT name
FROM residential_zones
WHERE ST_Within(
geom,
ST_GeomFromText('POLYGON((116.38 39.88, 116.42 39.88, 116.42 39.92, 116.38 39.92, 116.38 39.88))', 4326)
);
2.查询与指定几何对象相交的所有要素:
sql
-- 查询与一个圆形缓冲区相交的小区(缓冲区中心点 116.40,39.90,半径 200 米)
SELECT name
FROM residential_zones
WHERE ST_Intersects(
geom,
ST_Buffer(ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography, 200)::geometry
);
3.查询距离给定几何对象最近的要素:
sql
-- 查询离点 (116.405, 39.905) 最近的小区,并返回距离
SELECT name,
ST_Distance(geom::geography, ST_SetSRID(ST_MakePoint(116.405, 39.905), 4326)::geography) AS distance_m
FROM residential_zones
ORDER BY geom::geography <-> ST_SetSRID(ST_MakePoint(116.405, 39.905), 4326)::geography
LIMIT 1;
4.查询在指定距离内与给定几何对象相交的所有要素:
sql
-- 查询距离点 (116.40,39.90) 500 米范围内的小区
SELECT name
FROM residential_zones
WHERE ST_DWithin(
geom::geography,
ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography,
500
);
5.查询要素的面积:
sql
-- 查询每个小区的面积(平方米)
SELECT name, ST_Area(geom::geography) AS area_m2
FROM residential_zones;
6.查询要素的长度:
sql
-- 假设有一条河流表 rivers,包含线状字段 geom
SELECT name, ST_Length(geom::geography) AS length_m
FROM rivers;
三、PostGIS常用的空间关系判断语句
以下均以 residential_zones(多边形)和 point_of_interest(点表)为例。
-
ST_Equals(A, B):判断两个几何体是否完全相同
sqlSELECT ST_Equals(geom1, geom2) FROM ...; -
ST_Intersects(A, B):判断是否相交
sqlSELECT name FROM residential_zones WHERE ST_Intersects(geom, ST_SetSRID(ST_MakePoint(116.40,39.90), 4326)); -
ST_Contains(A, B):判断 A 是否包含 B
sqlSELECT r.name FROM residential_zones r, point_of_interest p WHERE ST_Contains(r.geom, p.geom) AND p.id = 1; -
ST_Within(A, B):判断 A 是否在 B 内部
sqlSELECT p.name FROM point_of_interest p, residential_zones r WHERE ST_Within(p.geom, r.geom) AND r.name = '东方花园'; -
ST_Touches(A, B):判断两个几何体是否接触(边界有公共点)
sqlSELECT a.name, b.name FROM residential_zones a, residential_zones b WHERE ST_Touches(a.geom, b.geom) AND a.id != b.id; -
ST_Overlaps(A, B):判断两个几何体是否重叠(同维度相交但不包含)
sqlSELECT a.name, b.name FROM residential_zones a, residential_zones b WHERE ST_Overlaps(a.geom, b.geom); -
ST_Crosses(A, B):判断是否交叉(如线穿过面)
sql-- 假设 roads 表有线状几何 SELECT r.name FROM roads r, residential_zones z WHERE ST_Crosses(r.geom, z.geom); -
ST_Disjoint(A, B):判断是否不相交
sqlSELECT name FROM residential_zones WHERE ST_Disjoint(geom, ST_SetSRID(ST_MakePoint(116.40,39.90), 4326)); -
ST_DWithin(A, B, distance):判断是否在指定距离内
sqlSELECT name FROM residential_zones WHERE ST_DWithin(geom::geography, ST_SetSRID(ST_MakePoint(116.40,39.90), 4326)::geography, 500);
四、数据导入导出语句
-
导出整个数据库
bashpg_dump -U postgres -h localhost gis_db > gis_db_backup.sql -
导出特定表
bashpg_dump -U postgres -h localhost -t residential_zones gis_db > residential_zones_backup.sql -
导入 SQL 文件
bashpsql -U postgres -h localhost gis_db < gis_db_backup.sql -
使用 COPY 导出 CSV
sql-- 将 residential_zones 表导出为 CSV,包含表头 COPY residential_zones (id, name, ST_AsText(geom)) TO '/tmp/residential_zones.csv' WITH CSV HEADER; -
使用 COPY 导入 CSV
sql-- 假设已有表结构,导入 CSV 数据(需确保几何字段为 WKT 文本) COPY residential_zones (id, name, geom) FROM '/tmp/residential_zones.csv' WITH CSV HEADER; -
导入 Shapefile 到 PostGIS
bash# 使用 shp2pgsql 将 shapefile 转换为 SQL 并导入数据库 shp2pgsql -s 4326 /path/to/housing.shp residential_zones | psql -d gis_db -U postgres -
导出 PostGIS 表为 Shapefile
bash# 使用 pgsql2shp 导出表为 shapefile pgsql2shp -f /tmp/housing.shp -h localhost -u postgres gis_db residential_zones