如何使用PostGIS扩展正确存储经纬度坐标值
问题描述
将地理编码接口返回的经纬度(纬度/经度)存储到PostGIS的GEOGRAPHY(Point)类型列时,部分经纬度查询返回值与插入值存在差异,需定位操作中的错误或遗漏。
复现步骤
执行以下SQL可复现问题:
CREATE EXTENSION IF NOT EXISTS postgis; CREATE TABLE "public"."test_location" ( "name" text, "location" GEOGRAPHY (point) ); INSERT INTO "public"."test_location" ("name", "location") VALUES ('test 1', ST_POINT (32.714476, -117.151735)), ('test 2', ST_POINT (36.1450444, -85.4788305)); SELECT name, ST_AsText (location) FROM "public"."test_location"; -- 输出结果: -- |-----------------------------------------| -- | name | ST_AsText | -- |-----------------------------------------| -- | test 1 | POINT(32.714476 -62.848265) | -- 预期为POINT(32.714476 -117.151735) -- | test 2 | POINT(36.1450444 -85.4788305) | -- |-----------------------------------------| DROP TABLE "public"."test_location";
问题原因
核心错误是坐标参数顺序传反,且未注意不同场景下的经纬度顺序约定差异:
- 地理编码接口返回的坐标顺序为「纬度在前,经度在后」,示例中32.714476、36.1450444为纬度值,-117.151735、-85.4788305为经度值
- PostGIS的
ST_POINT函数遵循OGC空间标准,参数顺序固定为ST_POINT(经度, 纬度),即x轴传经度、y轴传纬度 - 插入时直接按接口返回顺序传参,相当于把纬度填到了经度位、经度填到了纬度位:
- 第一条记录的第二个参数(误填入的经度值-117.151735)远小于纬度的合法下限-90,触发PostGIS自动坐标归一化折返计算:超出-90的部分为27.151735,折返后得到错误纬度值
-90 + 27.151735 = -62.848265,和返回结果完全吻合 - 第二条记录的第二个参数(误填入的经度值-85.4788305)刚好落在纬度合法范围[-90,90]内,没有触发折返,看起来数值和输入一致,实际坐标位置完全错误,落在南极附近区域,并非预期的北美地点。
- 第一条记录的第二个参数(误填入的经度值-117.151735)远小于纬度的合法下限-90,触发PostGIS自动坐标归一化折返计算:超出-90的部分为27.151735,折返后得到错误纬度值
修复方案
插入时调整参数顺序,将经度放在第一个参数位、纬度放在第二个参数位即可,修正后的插入语句:
INSERT INTO "public"."test_location" ("name", "location") VALUES ('test 1', ST_POINT (-117.151735, 32.714476)), ('test 2', ST_POINT (-85.4788305, 36.1450444));
为避免后续混淆参数顺序,推荐使用带命名参数的ST_MakePoint,同时显式声明坐标系SRID(WGS84坐标系对应SRID为4326,是通用GPS/在线地图使用的经纬度坐标系),语义更清晰:
INSERT INTO "public"."test_location" ("name", "location") VALUES ('test 1', ST_SetSRID(ST_MakePoint(lon => -117.151735, lat => 32.714476), 4326)), ('test 2', ST_SetSRID(ST_MakePoint(lon => -85.4788305, lat => 36.1450444), 4326));
内容的提问来源于stack exchange,提问作者user10645790
相关产品推荐
相关产品推荐

