QGIS 把geojson数据导入 PostgreSQL/PostGIS 的完整流程

示例数据(中国国界 + 省级行政区 GeoJSON,本文全程用这套数据演示): 链接:夸克网盘分享 提取码:Vysu (网盘失效请评论区留言,我看到会补)

前置阅读:先把环境装好

这篇是纯实操流程,不再重复讲安装。如果你还没装 PostgreSQL / PostGIS / QGIS,先看这两篇保姆级教程,跟着做一遍再回来:

本文假设你已经跑通了:本机 PostgreSQL 服务能启动、PostGIS 扩展能创建、QGIS 能加载 XYZ 底图。


做时空数据、监测类项目的朋友应该都遇到过这种场景:手里拿到一份 GeoJSON------可能是前端同事给的行政区边界、可能是无人机航测出的图斑、也可能是从 OSM 下载的路网------需要把它塞进 PostGIS 里做后续的空间查询、叠加分析或者瓦片服务发布。

命令行党会直接用 ogr2ogr 或者 shp2pgsql,但如果数据本身坐标系不干净、字段类型要调整、几何还有自相交需要修一修,纯命令行反而绕远。最省心的路径其实是 QGIS:图形化连接数据库、拖拽加载数据、右键导出入库,中间还能顺手做数据检查和坐标重投影。整个链路十几分钟就能跑通,比翻文档拼 SQL 快得多。

这篇把完整流程拆开写一遍,重点是几个新手容易踩坑的地方------SRID 选错、中文字段乱码、几何类型混杂、索引没建------都一并说清楚。示例数据用开头网盘里的中国国界和省界 GeoJSON,跟着做一遍就能复现。

一、准备工作:建库、启用扩展、看清数据

1.1 新建一个专用的 GIS 数据库

装完 PostgreSQL/PostGIS 之后,默认只有 postgrestemplate0template1 三个库,别直接把业务数据塞 postgres 库里,规范的做法是给 GIS 数据单开一个:

java 复制代码
-- 用 postgres 超级用户执行
CREATE DATABASE test_learn;
\c gis_demo
CREATE EXTENSION IF NOT EXISTS postgis;
​
-- 验证
SELECT PostGIS_Full_Version();

正常会返回类似 POSTGIS="3.4.1 xxxxx" [EXTENSION] PGSQL="150" 的版本串。扩展必须在目标库里手动 CREATE,很多新手以为装完 PostGIS 就全局可用,结果 QGIS 连上库却建不了空间表,卡在这里半天。

如果打算用 pgAdmin 图形化操作,也可以:Databases → 右键 → Create → Database,然后连上这个新库,在 Query Tool 里跑上面的 CREATE EXTENSION。

1.2 先看清 GeoJSON 长啥样

把网盘里的国界和省界 GeoJSON 下载下来,用 VSCode 或者在线 geojson.io 打开,确认三件事:

  • 顶层结构 :必须是 FeatureCollection,不能是单个 FeatureGeometry。QGIS 也能读单 Feature,但入库时容易只写一条记录,坑得很隐蔽。

  • 几何类型是否统一 :省界数据一般是 MultiPolygon(因为一个省可能包含多个岛屿飞地),国界可能是 PolygonMultiPolygon。混着来的话 PostGIS 会强制建成 GEOMETRY 通用类型,后续查询效率差、也不能建针对性的空间索引。

  • 坐标系:GeoJSON 规范(RFC 7946)默认要求 WGS84(EPSG:4326),但国内数据经常被人塞成 GCJ-02 火星坐标或者 CGCS2000,肉眼看不出来,导到底图上偏移几百米才发现。网盘里这两份数据是标准 WGS84,直接可用;你手上如果拿到别的数据,得留个心眼,第 3 节讲怎么处理。

二、QGIS 连接 PostGIS 数据库

打开 QGIS,左侧 Browser 面板(浏览器)找到 PostGIS 节点,右键 → 新建连接

弹窗里几个关键字段:

字段 说明
名称 test_learn 自己起,QGIS 里显示的别名
主机 localhost 远程库填 IP 或域名
端口 5432 PostgreSQL 默认端口
数据库 test_learn 上面 CREATE DATABASE 建的那个
用户名 postgres 或者专门的 GIS 用户
密码 ** 勾选"保存密码"省得每次输

关键的两个勾选项

  • 允许无密码保存:配合项目文件切换时不用反复输密码。

  • 只列出拥有权限的图层 :新手建议取消勾选,否则你自己刚导入的表可能因为权限过滤看不到,还以为导入失败了。

点"测试连接",弹窗显示连接成功就 OK。这时候 Browser 面板 PostGIS 下会展开你的连接,能看到 public schema 里已有的空间表(如果之前有的话)以及 spatial_ref_sys 这张系统表。

常见连接问题

Q: 测试连接报 "FATAL: password authentication failed"

检查 pg_hba.conf(PostgreSQL data 目录下),把本地连接方式从 scram-sha-256 改成 md5 或者临时改成 trust 测试,改完记得重启 PostgreSQL 服务。生产环境别用 trust。

Q: 报 "connection refused"

十有八九是 PostgreSQL 服务没启动,或者端口被占。Windows 服务里找 postgresql-x64-15 手动启动,或者 netstat -ano | findstr 5432 看端口监听情况。

Q: 远程库连不上,本地能连

默认 PostgreSQL 只监听 localhost,需要改 postgresql.conf 里的 listen_addresses = '*',同时在 pg_hba.conf 加一条 host all all 0.0.0.0/0 md5(生产环境把 0.0.0.0/0 换成具体网段),改完重启服务,防火墙放行 5432。

三、加载 GeoJSON 到 QGIS

三种方式任选一种:

  1. 直接拖拽:从资源管理器把 .geojson 文件拖到 QGIS 画布,最省事。

  2. 菜单加载:Layer → Add Layer → Add Vector Layer,数据源类型选"文件",浏览选中 GeoJSON。

  3. Browser 面板:如果文件在 QGIS 已注册的目录里,直接双击。

把网盘里的国界和省界两份数据都加载进来,配上底图看一眼,中国轮廓清晰、各省分界连续,说明数据本身没问题。

加载成功后左侧 Layers 面板会出现图层名,画布上显示矢量要素。这时候先别急着导出,做两件检查工作:

3.1 检查坐标系

右键图层 → 点击属性。看 CRS 那一行,坐标系那一栏会显示 EPSG 编码。

如果显示 EPSG:4326 - WGS 84,正常,跳到下一步。

如果显示 EPSG:3857 或者其他投影坐标系,说明数据已经是投影过的,需要判断入库用哪个 CRS。经验法则:

  • 展示、瓦片服务、Web 端:入 EPSG:3857(Web Mercator)或者 4326 都行,看后端约定。

  • 面积/长度计算、缓冲区分析:入投影坐标系,比如国内用 CGCS2000 3-degree Gauss-Kruger 带(EPSG:4513-4533 系列),单位是米,算出来才是真米。

  • 不确定就统一 4326 :PostGIS 里后续可以用 ST_Transform 现算。

如果需要改坐标系:右键图层 → 导出 → 要素另存为,在 CRS 下拉里选目标坐标系,导出成一个新的临时 GeoJSON 或者 Shapefile,再把这个中间产物入库。也可以在导入 PostGIS 那一步直接指定目标 CRS(下一节讲)。

踩坑提醒:国内项目常见的偏移问题,多数是 GeoJSON 存的是 GCJ-02 但声明成 WGS84,QGIS 认不出来,直接入 WGS84 底图会偏 100-500 米。这种情况得先用 coordtransform 之类的库做 GCJ-02 → WGS84 转换,QGIS 本身没有内置这个转换(因为它不是官方 EPSG 定义)。

3.2 检查几何有效性

Processing Toolbox(Ctrl+Alt+T 打开)里搜 Check Validity,运行后会给出一份无效几何清单。常见的自相交、环方向错误,可以用 Fix Geometries 工具一键修复,输出一个新的临时图层,用这个修复版去入库。

国界和省界这类公开数据一般几何都很干净,这步可以跳过;但如果是从 CAD 转过来的、或者前端同事用 d3-geo 手撸出来的 GeoJSON,最好过一遍。判断标准:入库后跑 ST_Intersects 之类的分析报错 GEOSIntersects: TopologyException,八成就是几何无效,回来补做。

四、导出到 PostGIS:两种方式对比

方式一:数据库管理器

点击上方的工具栏中的数据库,然后点击数据库管理器,选择要导入的数据库,然后点击导入图层或文件。

下面是导入的选项说明

点 OK,QGIS 底部状态栏会显示进度。省界数据大约三十几条记录、几万个顶点,几秒就导完;国界数据顶点更多一些,十几秒也够了。完成后 Browser 面板刷新,能在 test_learn → public 下看到 china_provincechina_border 两张新表,双击就能加载回画布验证。

方式二:DB Manager 插件(适合批量、需要写 SQL 前后处理)

菜单 Database → DB Manager,左侧树展开 PostGIS → test_learn,选中目标 schema,上方工具栏点 Import Layer/File 图标。

弹窗比 Export 简洁一些,多了几个选项:

  • Source SRID / Target SRID:可以显式指定,做坐标系转换更可控。

  • Create single-part geometries instead of multi-part:同上。

  • Replace all selected columns with strings:所有属性字段强制转 text,防止数值类型推断错误。

DB Manager 还有个杀手锏是内置 SQL 窗口,可以导入前先在源图层跑一段 SQL 做过滤:

java 复制代码
SELECT * FROM china_province
WHERE name LIKE '%河南%'
  AND ST_IsValid(geom)

然后再导入。这种"边导边筛"的能力,右键 Export 做不到。如果只想把某几个省单独入一张表做重点分析,走这条路。

两种方式怎么选

  • 单个图层、字段类型清晰、直接入库:Export。

  • 多个图层批量、需要 SQL 预处理、需要精细控制 SRID:DB Manager。

  • 需要写入非 public schema 且 schema 尚未创建 :先在 DB Manager 或者 psql 里 CREATE SCHEMA xxx;,再回来导入,Export 不能自动建 schema。

五、验证与后续处理

5.1 psql 里查一下

java 复制代码
-- 表结构
\d public.china_province
​
-- 记录数
SELECT COUNT(*) FROM china_province;
​
-- 几何类型和 SRID 确认
SELECT GeometryType(geom), ST_SRID(geom) FROM china_province LIMIT 1;
​
-- 空间范围(应该覆盖中国全域,经度 73-135,纬度 3-54 左右)
SELECT ST_Extent(geom) FROM china_province;
​
-- 索引情况
SELECT indexname, indexdef FROM pg_indexes
WHERE tablename = 'china_province';
​
-- 抽样看几条属性
SELECT name, ST_Area(geom::geography)/1e6 AS area_km2
FROM china_province
ORDER BY area_km2 DESC
LIMIT 5;

应该能看到 geom geometry(MultiPolygon,4326) 这样的字段类型,索引里应该有一条 gist (geom)。最后那条面积查询会返回新疆、西藏、内蒙古这几个大区,能对上就说明数据、坐标系、投影都没问题。

5.2 QGIS 里加载回来看看

Browser 面板找到刚导入的表,双击加载。如果画布上什么都不显示,先点工具栏的 Zoom Full(放大镜图标),大概率是视图没定位到数据范围。

右键图层 → Properties → Source,看 Features count 是否和 psql 查出来的记录数一致。

再顺手做个直观验证:把 QGIS 底图切到天地图或者 OSM,看看 PostGIS 里的省界是不是完美贴合底图轮廓。有偏移的话就是坐标系问题,回头查第三节。

5.3 补建索引(如果导入时漏了)

java 复制代码
CREATE INDEX idx_china_province_geom
  ON china_province USING GIST (geom);
​
-- 更新统计信息,让查询规划器走对索引
ANALYZE china_province;

省界这种规模的数据其实无所谓,但如果你导的是百万级路网或者上亿点云,建议再补一个:

java 复制代码
-- 空间聚类,让物理存储顺序和空间位置贴近,范围查询提速明显
CLUSTER china_province USING idx_china_province_geom;

CLUSTER 是一次性操作,后续新增数据不会自动重排,定期维护的话可以配 pg_cron 定时跑。

六、常见坑与排查清单

坑 1:中文字段乱码

现象:psql 查出来 name 字段是 ??? 或者一串拉丁字母乱码,比如 河南省 变成 ?ê??

原因:GeoJSON 是 UTF-8,但导入时 Encoding 选了 System(Windows 下就是 GBK)。

修复:Export 对话框 Encoding 明确选 UTF-8,重新导一次。已经入库的可以:

java 复制代码
ALTER TABLE china_province
  ALTER COLUMN name TYPE text
  USING convert_from(convert_to(name, 'GBK'), 'UTF8');

不过说实话,重新导比转换靠谱。

坑 2:几何类型不匹配

现象:QGIS 加载入库表时报 "WKB type MultiPolygon not supported by this layer"。

原因:Export 时选了 "Force single-part",把 MultiPolygon 拆成了 Polygon,但图层元数据还写着 Multi。

修复:删表重导,或者 QGIS 里 Layer → Add Layer 时手动指定几何类型。

坑 3:SRID 0 或者 -1

现象:SELECT ST_SRID(geom) 返回 0。

原因:GeoJSON 文件里没写 crs 字段,QGIS 也没识别出来,导入时 CRS 下拉框被留成"未知"。

修复:入库时明确选 EPSG:4326,或者事后 UPDATE:

java 复制代码
UPDATE china_province
  SET geom = ST_SetSRID(geom, 4326);

注意 ST_SetSRID 只改标签不做坐标变换,如果原始坐标本来就是经纬度那没问题;如果是投影坐标被误标成 4326,得用 ST_Transform 重算。

坑 4:远程库导入极慢

现象:本机导几万条秒完,远程库卡半小时。

原因:QGIS 是逐条 INSERT,网络往返放大延迟。

修复:Export 对话框下方有个 Use bulk insert 或者切换到 DB Manager 用 COPY 模式,速度能提一到两个数量级。或者干脆把 GeoJSON 传到服务器本地,用 ogr2ogr 命令行导,那是最快的。

坑 5:权限不足

现象:连得上库,但导入时报 permission denied for schema public

原因:PostgreSQL 15 之后,public schema 默认不再给普通用户 CREATE 权限。

修复:用超级用户执行:

java 复制代码
GRANT CREATE, USAGE ON SCHEMA public TO gis_user;
-- 或者更规范地建独立 schema
CREATE SCHEMA gis_data AUTHORIZATION gis_user;

七、写在最后

用 QGIS 把 GeoJSON 塞进 PostGIS 这条路,胜在可视化、可回溯、中间能改 ,特别适合数据本身不太干净、需要边看边调的场景。等流程稳定了、数据结构固化了,再切换到 ogr2ogr 或者 Python 脚本批处理也不迟。

如果这篇文章对你有用,点个赞、收藏一下,评论区聊聊你入库时遇到的奇葩数据格式。

相关推荐
虎虎(_ _)。゜zzZ1 小时前
Qdrant向量数据库工程实战
数据库·人工智能·大模型·向量数据库·rag·qdrant
ZGG0031 小时前
线程池详解:从 7 大参数到生产避坑
java·数据库·后端
龙亘川2 小时前
数智赋能退役军人服务:V1.0 系统搭建全生命周期闭环服务体系
大数据·数据库·人工智能
zhangguojia72 小时前
权限弹窗点击允许的授权流程
运维·服务器·数据库
jnrjian2 小时前
Postgres 序列(sequence)的权限
数据库·postgresql
风禾万里2 小时前
【无标题】
数据库
镜舟科技2 小时前
为什么 Text-to-SQL 总是停在 Demo?
数据库·sql·demo·text-to-sql·镜舟科技·mip·语义视图
人生苦短1282 小时前
Oracle RAC 日常管理+排错命令大全
数据库·oracle
镜舟科技2 小时前
从 DBA 经验到 Agent:镜舟如何构建生产级智能排障体系
数据库·agent·dba·skill·devops agent·mirrorship