第03章-空间数据类型详解
第03章:空间数据类型详解
3.1 PostGIS 数据类型概述
PostGIS 提供了多种空间数据类型来存储和处理地理信息。理解这些数据类型是使用 PostGIS 的基础。
3.1.1 数据类型分类
┌─────────────────────────────────────────────────────────────┐
│ PostGIS 空间数据类型 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 矢量数据类型 │
│ ├── Geometry (几何类型) │
│ │ ├── 平面坐标系统 │
│ │ ├── 笛卡尔运算 │
│ │ └── 更多函数支持 │
│ │ │
│ └── Geography (地理类型) │
│ ├── 球面坐标系统 │
│ ├── 大地测量计算 │
│ └── 经纬度坐标 │
│ │
│ 栅格数据类型 │
│ └── Raster (栅格类型) │
│ ├── 像素网格数据 │
│ ├── 多波段支持 │
│ └── 空间分析功能 │
│ │
│ 拓扑数据类型 │
│ └── Topology (拓扑类型) │
│ ├── 节点、边、面 │
│ ├── 拓扑规则 │
│ └── 数据完整性 │
│ │
└─────────────────────────────────────────────────────────────┘
3.1.2 几何类型层次结构
PostGIS 的几何类型遵循 OGC Simple Features 规范:
Geometry
│
┌────────────────────┼────────────────────┐
│ │ │
Point Curve Surface
│ │ │
│ ┌─────────────┼─────────────┐ │
│ │ │ │ │
│ LineString CircularString CompoundCurve
│ │ │
│ │ Polygon
│ │ │
│ │ CurvePolygon
│ │
MultiPoint │
│
MultiLineString
│
MultiPolygon
│
GeometryCollection
3.1.3 类型定义语法
-- 完整的类型定义语法
GEOMETRY(geometry_type, srid)
GEOGRAPHY(geometry_type, srid)
-- geometry_type 可选值:
-- POINT, LINESTRING, POLYGON
-- MULTIPOINT, MULTILINESTRING, MULTIPOLYGON
-- GEOMETRYCOLLECTION
-- POINTZ, LINESTRINGZ, POLYGONZ (带 Z 值)
-- POINTM, LINESTRINGM, POLYGONM (带 M 值)
-- POINTZM, LINESTRINGZM, POLYGONZM (带 ZM 值)
-- 示例
CREATE TABLE points (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
geom GEOMETRY(POINT, 4326)
);
CREATE TABLE lines (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
geom GEOMETRY(LINESTRING, 4326)
);
CREATE TABLE polygons (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
geom GEOMETRY(POLYGON, 4326)
);
-- 不指定类型(可存储任意几何类型)
CREATE TABLE mixed_geometries (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
geom GEOMETRY
);
3.2 Geometry 类型详解
3.2.1 Point(点)
点是最简单的几何类型,表示空间中的一个位置。
结构定义
-- 2D 点
POINT(x y)
-- 例如:POINT(116.4074 39.9042)
-- 3D 点(带高程)
POINT Z(x y z)
-- 例如:POINT Z(116.4074 39.9042 45.5)
-- 带测量值的点
POINT M(x y m)
-- 例如:POINT M(116.4074 39.9042 100.0)
-- 带高程和测量值的点
POINT ZM(x y z m)
-- 例如:POINT ZM(116.4074 39.9042 45.5 100.0)
创建点的方法
-- 使用 ST_MakePoint
SELECT ST_MakePoint(116.4074, 39.9042);
SELECT ST_MakePoint(116.4074, 39.9042, 45.5); -- 3D
SELECT ST_MakePointM(116.4074, 39.9042, 100.0); -- 带 M 值
-- 使用 ST_GeomFromText (WKT)
SELECT ST_GeomFromText('POINT(116.4074 39.9042)', 4326);
SELECT ST_GeomFromText('POINT Z(116.4074 39.9042 45.5)', 4326);
-- 使用 ST_SetSRID 设置空间参考
SELECT ST_SetSRID(ST_MakePoint(116.4074, 39.9042), 4326);
-- 使用 ST_Point(PostGIS 3.0+)
SELECT ST_Point(116.4074, 39.9042, 4326);
-- 从经纬度创建(注意经度在前)
SELECT ST_SetSRID(ST_MakePoint(116.4074, 39.9042), 4326);
点的常用操作
-- 创建点表
CREATE TABLE poi (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
category VARCHAR(50),
geom GEOMETRY(POINT, 4326)
);
-- 插入数据
INSERT INTO poi (name, category, geom) VALUES
('故宫', '景点', ST_SetSRID(ST_MakePoint(116.3972, 39.9169), 4326)),
('天安门', '景点', ST_SetSRID(ST_MakePoint(116.3912, 39.9055), 4326)),
('王府井', '商业', ST_SetSRID(ST_MakePoint(116.4104, 39.9142), 4326));
-- 获取点坐标
SELECT name, ST_X(geom) AS lng, ST_Y(geom) AS lat FROM poi;
-- 计算两点距离(米)
SELECT
a.name AS from_poi,
b.name AS to_poi,
ST_Distance(a.geom::geography, b.geom::geography) AS distance_m
FROM poi a, poi b
WHERE a.id < b.id;
-- 查找某点附近的 POI
SELECT name, ST_Distance(geom::geography,
ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326)::geography) AS distance
FROM poi
WHERE ST_DWithin(geom::geography,
ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326)::geography, 1000)
ORDER BY distance;
3.2.2 LineString(线)
线由有序的点序列组成,表示路径或边界。
结构定义
-- 2D 线
LINESTRING(x1 y1, x2 y2, ..., xn yn)
-- 例如:LINESTRING(116.3 39.9, 116.4 39.95, 116.5 39.9)
-- 3D 线
LINESTRING Z(x1 y1 z1, x2 y2 z2, ..., xn yn zn)
-- 环形线(首尾相连)
LINESTRING(x1 y1, x2 y2, x3 y3, x1 y1)
创建线的方法
-- 使用 ST_MakeLine(从点创建)
SELECT ST_MakeLine(
ST_MakePoint(116.3, 39.9),
ST_MakePoint(116.5, 39.95)
);
-- 从点数组创建
SELECT ST_MakeLine(ARRAY[
ST_MakePoint(116.3, 39.9),
ST_MakePoint(116.4, 39.95),
ST_MakePoint(116.5, 39.9)
]);
-- 使用 ST_GeomFromText (WKT)
SELECT ST_GeomFromText('LINESTRING(116.3 39.9, 116.4 39.95, 116.5 39.9)', 4326);
-- 使用 ST_GeomFromGeoJSON
SELECT ST_GeomFromGeoJSON('{"type":"LineString","coordinates":[[116.3,39.9],[116.4,39.95],[116.5,39.9]]}');
线的常用操作
-- 创建道路表
CREATE TABLE roads (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
road_type VARCHAR(50),
geom GEOMETRY(LINESTRING, 4326)
);
-- 插入数据
INSERT INTO roads (name, road_type, geom) VALUES
('长安街', '主干道', ST_GeomFromText('LINESTRING(116.28 39.9055, 116.32 39.9055, 116.39 39.9055, 116.46 39.9055)', 4326)),
('建国门外大街', '主干道', ST_GeomFromText('LINESTRING(116.39 39.9055, 116.46 39.906, 116.52 39.906)', 4326));
-- 计算线长度(米)
SELECT name, ST_Length(geom::geography) AS length_m FROM roads;
-- 获取起点和终点
SELECT name,
ST_AsText(ST_StartPoint(geom)) AS start_point,
ST_AsText(ST_EndPoint(geom)) AS end_point
FROM roads;
-- 获取线上的点数
SELECT name, ST_NPoints(geom) AS point_count FROM roads;
-- 获取线的中点
SELECT name, ST_AsText(ST_LineInterpolatePoint(geom, 0.5)) AS mid_point FROM roads;
-- 线段分割
SELECT name, ST_AsText((ST_Dump(ST_Segmentize(geom::geography, 1000)::geometry)).geom) AS segments
FROM roads;
-- 合并多条线
SELECT ST_AsText(ST_LineMerge(ST_Collect(geom))) AS merged_line FROM roads;
-- 判断线是否闭合
SELECT name, ST_IsClosed(geom) AS is_closed FROM roads;
-- 简化线
SELECT name, ST_AsText(ST_Simplify(geom, 0.001)) AS simplified FROM roads;
3.2.3 Polygon(多边形)
多边形由一个外环和零个或多个内环(孔洞)组成。
结构定义
-- 简单多边形(无孔洞)
POLYGON((x1 y1, x2 y2, x3 y3, x1 y1))
-- 例如:POLYGON((116.3 39.8, 116.5 39.8, 116.5 40.0, 116.3 40.0, 116.3 39.8))
-- 带孔洞的多边形
POLYGON((外环坐标), (内环1坐标), (内环2坐标), ...)
-- 例如:POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (2 2, 8 2, 8 8, 2 8, 2 2))
-- 3D 多边形
POLYGON Z((x1 y1 z1, x2 y2 z2, x3 y3 z3, x1 y1 z1))
创建多边形的方法
-- 使用 ST_GeomFromText (WKT)
SELECT ST_GeomFromText('POLYGON((116.3 39.8, 116.5 39.8, 116.5 40.0, 116.3 40.0, 116.3 39.8))', 4326);
-- 使用 ST_MakePolygon(从闭合线创建)
SELECT ST_MakePolygon(
ST_GeomFromText('LINESTRING(116.3 39.8, 116.5 39.8, 116.5 40.0, 116.3 40.0, 116.3 39.8)', 4326)
);
-- 带孔洞的多边形
SELECT ST_MakePolygon(
ST_GeomFromText('LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0)', 4326),
ARRAY[ST_GeomFromText('LINESTRING(2 2, 8 2, 8 8, 2 8, 2 2)', 4326)]
);
-- 使用 ST_MakeEnvelope 创建矩形
SELECT ST_MakeEnvelope(116.3, 39.8, 116.5, 40.0, 4326);
-- 使用 ST_Buffer 从点创建圆形
SELECT ST_Buffer(ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326)::geography, 1000)::geometry;
-- 使用 ST_GeomFromGeoJSON
SELECT ST_GeomFromGeoJSON('{"type":"Polygon","coordinates":[[[116.3,39.8],[116.5,39.8],[116.5,40.0],[116.3,40.0],[116.3,39.8]]]}');
多边形的常用操作
-- 创建行政区表
CREATE TABLE districts (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
code VARCHAR(20),
geom GEOMETRY(POLYGON, 4326)
);
-- 插入数据
INSERT INTO districts (name, code, geom) VALUES
('东城区', '110101', ST_GeomFromText('POLYGON((116.38 39.88, 116.44 39.88, 116.44 39.95, 116.38 39.95, 116.38 39.88))', 4326)),
('西城区', '110102', ST_GeomFromText('POLYGON((116.32 39.88, 116.38 39.88, 116.38 39.95, 116.32 39.95, 116.32 39.88))', 4326));
-- 计算面积(平方米)
SELECT name, ST_Area(geom::geography) AS area_m2 FROM districts;
-- 计算面积(平方公里)
SELECT name, ST_Area(geom::geography) / 1000000.0 AS area_km2 FROM districts;
-- 获取边界周长
SELECT name, ST_Perimeter(geom::geography) AS perimeter_m FROM districts;
-- 获取边界
SELECT name, ST_AsText(ST_Boundary(geom)) AS boundary FROM districts;
-- 获取外环
SELECT name, ST_AsText(ST_ExteriorRing(geom)) AS exterior_ring FROM districts;
-- 获取质心
SELECT name, ST_AsText(ST_Centroid(geom)) AS centroid FROM districts;
-- 获取内部点(保证在多边形内)
SELECT name, ST_AsText(ST_PointOnSurface(geom)) AS point_on_surface FROM districts;
-- 判断是否有效
SELECT name, ST_IsValid(geom) AS is_valid FROM districts;
-- 修复无效多边形
UPDATE districts SET geom = ST_MakeValid(geom) WHERE NOT ST_IsValid(geom);
-- 简化多边形
SELECT name, ST_AsText(ST_Simplify(geom, 0.001)) AS simplified FROM districts;
-- 判断点是否在多边形内
SELECT d.name
FROM districts d
WHERE ST_Contains(d.geom, ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326));
3.2.4 MultiPoint(多点)
-- 创建多点
SELECT ST_GeomFromText('MULTIPOINT((116.3 39.9), (116.4 39.95), (116.5 39.9))', 4326);
-- 使用 ST_Collect 合并点
SELECT ST_Collect(geom) FROM poi;
-- 从多点获取单个点
SELECT ST_AsText((ST_Dump(ST_GeomFromText('MULTIPOINT((116.3 39.9), (116.4 39.95))', 4326))).geom);
-- 获取点数量
SELECT ST_NumGeometries(ST_GeomFromText('MULTIPOINT((116.3 39.9), (116.4 39.95))', 4326));
3.2.5 MultiLineString(多线)
-- 创建多线
SELECT ST_GeomFromText('MULTILINESTRING((116.3 39.9, 116.4 39.95), (116.4 39.95, 116.5 39.9))', 4326);
-- 合并线
SELECT ST_LineMerge(ST_Collect(geom)) FROM roads;
-- 计算总长度
SELECT ST_Length(ST_Collect(geom)::geography) FROM roads;
3.2.6 MultiPolygon(多面)
-- 创建多面
SELECT ST_GeomFromText('MULTIPOLYGON(((0 0, 1 0, 1 1, 0 1, 0 0)), ((2 2, 3 2, 3 3, 2 3, 2 2)))', 4326);
-- 合并多边形
SELECT ST_Union(geom) FROM districts;
-- 计算总面积
SELECT ST_Area(ST_Union(geom)::geography) FROM districts;
3.2.7 GeometryCollection(几何集合)
-- 创建几何集合
SELECT ST_GeomFromText('GEOMETRYCOLLECTION(POINT(116.4 39.9), LINESTRING(116.3 39.8, 116.5 39.8))', 4326);
-- 收集不同类型的几何
SELECT ST_Collect(ARRAY[
ST_MakePoint(116.4, 39.9),
ST_MakeLine(ST_MakePoint(116.3, 39.8), ST_MakePoint(116.5, 39.8))
]);
-- 获取集合中的几何数量
SELECT ST_NumGeometries(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(1 1, 2 2))', 4326));
-- 获取特定索引的几何
SELECT ST_AsText(ST_GeometryN(
ST_GeomFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(1 1, 2 2))', 4326),
1
));
3.3 Geography 类型详解
3.3.1 Geography 与 Geometry 的区别
| 特性 | Geometry | Geography |
|---|---|---|
| 坐标系 | 平面(笛卡尔) | 球面(大地) |
| 单位 | 度或投影单位 | 度(经纬度) |
| 距离计算 | 平面距离 | 大地测量距离 |
| 面积计算 | 平面面积 | 球面面积 |
| 函数数量 | 1000+ | 100+ |
| 性能 | 较快 | 较慢 |
| 适用范围 | 小区域 | 大区域/全球 |
| SRID 支持 | 任意 | 4326 等 |
3.3.2 使用 Geography 类型
-- 创建使用 Geography 的表
CREATE TABLE cities_geo (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
population INTEGER,
geog GEOGRAPHY(POINT, 4326)
);
-- 插入数据
INSERT INTO cities_geo (name, population, geog) VALUES
('北京', 21540000, ST_GeographyFromText('POINT(116.4074 39.9042)')),
('上海', 24870000, ST_GeographyFromText('POINT(121.4737 31.2304)')),
('纽约', 8336817, ST_GeographyFromText('POINT(-74.0060 40.7128)'));
-- Geography 类型自动使用球面计算
-- 计算北京到上海的距离(米)
SELECT ST_Distance(
(SELECT geog FROM cities_geo WHERE name = '北京'),
(SELECT geog FROM cities_geo WHERE name = '上海')
) AS distance_m;
-- 计算北京到纽约的距离(公里)
SELECT ST_Distance(
(SELECT geog FROM cities_geo WHERE name = '北京'),
(SELECT geog FROM cities_geo WHERE name = '纽约')
) / 1000.0 AS distance_km;
3.3.3 Geometry 与 Geography 转换
-- Geometry 转 Geography
SELECT geom::geography FROM poi;
-- Geography 转 Geometry
SELECT geog::geometry FROM cities_geo;
-- 使用 ST_Transform 进行投影转换后再转换
SELECT ST_Transform(geom, 3857)::geography FROM poi WHERE ST_SRID(geom) = 4326;
3.3.4 选择 Geometry 还是 Geography
使用 Geography 的场景:
- 需要精确的大地测量计算
- 数据跨越大范围区域(跨省、跨国)
- 需要计算真实的地球表面距离
- 数据使用经纬度坐标(WGS84)
使用 Geometry 的场景:
- 需要更多空间函数支持
- 数据范围较小(城市级别)
- 已有投影坐标数据
- 性能要求较高
-- 小范围数据示例(北京市内)
-- 使用 Geometry 配合投影坐标
CREATE TABLE beijing_poi (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
geom GEOMETRY(POINT, 4527) -- CGCS2000 / 3-degree Gauss-Kruger zone 39
);
-- 大范围数据示例(全球城市)
-- 使用 Geography
CREATE TABLE world_cities (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
country VARCHAR(100),
geog GEOGRAPHY(POINT, 4326)
);
3.4 坐标维度与测量值
3.4.1 二维几何(XY)
-- 标准 2D 几何
CREATE TABLE table_2d (
id SERIAL PRIMARY KEY,
geom GEOMETRY(POINT, 4326)
);
INSERT INTO table_2d (geom) VALUES
(ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326));
-- 检查维度
SELECT ST_NDims(geom), ST_CoordDim(geom) FROM table_2d;
-- 结果: 2, 2
3.4.2 三维几何(XYZ)
-- 带高程的 3D 几何
CREATE TABLE table_3d (
id SERIAL PRIMARY KEY,
geom GEOMETRY(POINTZ, 4326)
);
INSERT INTO table_3d (geom) VALUES
(ST_SetSRID(ST_MakePoint(116.4, 39.9, 45.5), 4326));
-- 获取 Z 值
SELECT ST_Z(geom) AS elevation FROM table_3d;
-- 3D 距离计算
SELECT ST_3DDistance(
ST_SetSRID(ST_MakePoint(0, 0, 0), 4326),
ST_SetSRID(ST_MakePoint(1, 1, 1), 4326)
) AS distance_3d;
-- 3D 长度计算
SELECT ST_3DLength(
ST_SetSRID(ST_GeomFromText('LINESTRING Z(0 0 0, 1 1 1, 2 2 2)'), 4326)
) AS length_3d;
3.4.3 带测量值的几何(XYM)
-- 带测量值的几何(如里程标记)
CREATE TABLE table_m (
id SERIAL PRIMARY KEY,
geom GEOMETRY(POINTM, 4326)
);
INSERT INTO table_m (geom) VALUES
(ST_SetSRID(ST_MakePointM(116.4, 39.9, 1000.0), 4326));
-- 获取 M 值
SELECT ST_M(geom) AS measure FROM table_m;
-- 线性参考示例
-- 创建带里程的道路
CREATE TABLE road_with_measures (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
geom GEOMETRY(LINESTRINGM, 4326)
);
INSERT INTO road_with_measures (name, geom) VALUES
('测试路', ST_SetSRID(ST_GeomFromText('LINESTRING M(0 0 0, 1 0 500, 2 0 1000)'), 4326));
-- 根据 M 值定位点
SELECT ST_AsText(ST_LocateAlong(geom, 500)) FROM road_with_measures;
3.4.4 四维几何(XYZM)
-- 完整的 4D 几何
CREATE TABLE table_4d (
id SERIAL PRIMARY KEY,
geom GEOMETRY(POINTZM, 4326)
);
INSERT INTO table_4d (geom) VALUES
(ST_SetSRID(ST_GeomFromText('POINT ZM(116.4 39.9 45.5 1000.0)'), 4326));
-- 获取所有坐标值
SELECT
ST_X(geom) AS x,
ST_Y(geom) AS y,
ST_Z(geom) AS z,
ST_M(geom) AS m
FROM table_4d;
3.5 类型修饰符与约束
3.5.1 几何类型约束
-- 使用类型修饰符
CREATE TABLE constrained_table (
id SERIAL PRIMARY KEY,
-- 只允许 Point 类型
point_geom GEOMETRY(POINT, 4326),
-- 只允许 Polygon 类型
polygon_geom GEOMETRY(POLYGON, 4326),
-- 允许任意几何类型
any_geom GEOMETRY(GEOMETRY, 4326)
);
-- 使用 CHECK 约束
CREATE TABLE check_constrained (
id SERIAL PRIMARY KEY,
geom GEOMETRY(GEOMETRY, 4326),
CONSTRAINT enforce_geom_type CHECK (GeometryType(geom) IN ('POINT', 'LINESTRING'))
);
-- 使用 AddGeometryColumn(传统方式)
CREATE TABLE old_style (id SERIAL PRIMARY KEY);
SELECT AddGeometryColumn('old_style', 'geom', 4326, 'POINT', 2);
3.5.2 SRID 约束
-- 强制 SRID
CREATE TABLE srid_constrained (
id SERIAL PRIMARY KEY,
geom GEOMETRY(POINT, 4326),
-- 自动添加 SRID 约束
CONSTRAINT enforce_srid CHECK (ST_SRID(geom) = 4326)
);
-- 插入数据时会自动验证 SRID
INSERT INTO srid_constrained (geom) VALUES
(ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326)); -- 成功
-- 以下会失败
-- INSERT INTO srid_constrained (geom) VALUES
-- (ST_SetSRID(ST_MakePoint(116.4, 39.9), 3857)); -- 错误:SRID 不匹配
3.5.3 有效性约束
-- 确保几何有效性
CREATE TABLE valid_geometries (
id SERIAL PRIMARY KEY,
geom GEOMETRY(POLYGON, 4326),
CONSTRAINT enforce_valid CHECK (ST_IsValid(geom))
);
-- 自动修复触发器
CREATE OR REPLACE FUNCTION fix_geometry()
RETURNS TRIGGER AS $$
BEGIN
IF NOT ST_IsValid(NEW.geom) THEN
NEW.geom = ST_MakeValid(NEW.geom);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trigger_fix_geometry
BEFORE INSERT OR UPDATE ON valid_geometries
FOR EACH ROW EXECUTE FUNCTION fix_geometry();
3.6 空间数据存储
3.6.1 内部存储格式
PostGIS 使用 EWKB(Extended Well-Known Binary)格式存储几何数据:
-- 查看内部存储格式
SELECT geom FROM poi LIMIT 1;
-- 返回十六进制的 EWKB 格式
-- 查看 WKB
SELECT ST_AsBinary(geom) FROM poi LIMIT 1;
-- 查看 EWKB(包含 SRID)
SELECT ST_AsEWKB(geom) FROM poi LIMIT 1;
-- 查看存储大小
SELECT
pg_column_size(geom) AS bytes,
ST_MemSize(geom) AS memory_size
FROM poi LIMIT 1;
-- 估算表的几何数据大小
SELECT
pg_size_pretty(sum(pg_column_size(geom))) AS total_geom_size,
pg_size_pretty(pg_total_relation_size('poi')) AS total_table_size
FROM poi;
3.6.2 存储优化
-- 简化几何以减少存储
UPDATE large_polygons
SET geom = ST_Simplify(geom, 0.0001)
WHERE ST_NPoints(geom) > 1000;
-- 压缩几何
-- PostGIS 默认使用 PostgreSQL 的 TOAST 压缩
-- 设置列的存储策略
ALTER TABLE large_polygons ALTER COLUMN geom SET STORAGE EXTENDED;
-- PLAIN: 不压缩,不使用 TOAST
-- EXTENDED: 压缩后使用 TOAST(默认)
-- EXTERNAL: 不压缩,使用 TOAST
-- MAIN: 尽量不使用 TOAST
-- 查看存储策略
SELECT attname, attstorage
FROM pg_attribute
WHERE attrelid = 'large_polygons'::regclass AND attname = 'geom';
3.7 空间元数据
3.7.1 geometry_columns 视图
-- 查看所有空间表
SELECT * FROM geometry_columns;
-- 查看特定表的空间列信息
SELECT f_table_schema, f_table_name, f_geometry_column,
coord_dimension, srid, type
FROM geometry_columns
WHERE f_table_name = 'poi';
-- 手动更新元数据(不建议)
-- SELECT Populate_Geometry_Columns();
3.7.2 spatial_ref_sys 表
-- 查看可用的空间参考系统
SELECT srid, auth_name, auth_srid, srtext
FROM spatial_ref_sys
WHERE srid IN (4326, 3857, 4490);
-- 搜索特定投影
SELECT srid, auth_name || ':' || auth_srid AS code, srtext
FROM spatial_ref_sys
WHERE srtext LIKE '%China%' OR srtext LIKE '%Beijing%'
LIMIT 10;
-- 添加自定义空间参考系统
INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, srtext, proj4text)
VALUES (
990000,
'CUSTOM',
990000,
'PROJCS["Custom CRS", ...]',
'+proj=tmerc +lat_0=0 +lon_0=117 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs'
);
3.8 类型转换最佳实践
3.8.1 类型转换函数
-- 几何类型转换
-- 点转多点
SELECT ST_Multi(ST_MakePoint(116.4, 39.9));
-- 线转多线
SELECT ST_Multi(ST_MakeLine(ST_MakePoint(0, 0), ST_MakePoint(1, 1)));
-- 强制转换为 2D
SELECT ST_Force2D(ST_SetSRID(ST_MakePoint(116.4, 39.9, 45.5), 4326));
-- 强制转换为 3D
SELECT ST_Force3D(ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326));
-- 强制转换为 4D
SELECT ST_Force4D(ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326));
-- 转换几何类型
SELECT ST_CurveToLine(ST_GeomFromText('CIRCULARSTRING(0 0, 1 1, 2 0)', 4326));
3.8.2 安全转换
-- 安全的类型转换(带错误处理)
CREATE OR REPLACE FUNCTION safe_geom_cast(geom geometry, target_type text)
RETURNS geometry AS $$
DECLARE
result geometry;
BEGIN
IF GeometryType(geom) = upper(target_type) THEN
RETURN geom;
END IF;
CASE upper(target_type)
WHEN 'POINT' THEN
result := ST_Centroid(geom);
WHEN 'LINESTRING' THEN
result := ST_Boundary(geom);
WHEN 'POLYGON' THEN
IF GeometryType(geom) = 'LINESTRING' AND ST_IsClosed(geom) THEN
result := ST_MakePolygon(geom);
ELSE
result := ST_ConvexHull(geom);
END IF;
WHEN 'MULTIPOINT' THEN
result := ST_Multi(ST_Centroid(geom));
WHEN 'MULTILINESTRING' THEN
result := ST_Multi(ST_Boundary(geom));
WHEN 'MULTIPOLYGON' THEN
result := ST_Multi(ST_ConvexHull(geom));
ELSE
RAISE EXCEPTION 'Unsupported target type: %', target_type;
END CASE;
RETURN result;
END;
$$ LANGUAGE plpgsql;
3.9 本章小结
本章详细介绍了 PostGIS 的空间数据类型:
- 类型概述:了解了 Geometry、Geography、Raster 等类型
- Geometry 类型:深入学习了 Point、LineString、Polygon 等几何类型
- Geography 类型:理解了球面计算的优势和使用场景
- 坐标维度:掌握了 2D、3D、4D 几何的使用方法
- 类型约束:学习了几何类型和 SRID 约束的实现
- 存储格式:了解了 EWKB 格式和存储优化方法
- 空间元数据:掌握了 geometry_columns 和 spatial_ref_sys 的使用
3.10 下一步
在下一章中,我们将学习空间参考系统,包括:
- SRID 详解
- 常用坐标系统
- 坐标转换方法
- 中国常用坐标系
相关资源:

浙公网安备 33010602011771号