MySQL 8.0 ST_Contains查询坐标顺序报错问题咨询
我们正从MySQL 5.6升级至8.0,原有ST_Contains查询在5.6中正常运行,但在8.0及Workbench测试时返回错误:
Error Code: 3617. Latitude 127.000000 is out of range in function st_geomfromtext. It must be within [-90.000000, 90.000000].
我们在POLYGON和POINT中一直采用**x=经度(lon)、y=纬度(lat)**的格式,示例坐标均位于东南半球且所有经纬度值均在合法范围内。但从错误信息来看,系统似乎把f.lon当作纬度值进行范围校验,将坐标顺序改为x=纬度、y=经度后能得到正确结果。
疑问:WKT规范中是否应为x=经度、y=纬度?恳请相关技术解释与帮助。
复现代码
创建测试表
CREATE DATABASE IF NOT EXISTS `tempdata`; USE `tempdata`; DROP TABLE IF EXISTS `sample`; CREATE TABLE `sample` ( `Place` char(10) NOT NULL, `Lat` decimal(10,8) DEFAULT NULL, `Lon` decimal(11,8) DEFAULT NULL, PRIMARY KEY (`Place`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; INSERT INTO `sample` VALUES ('IN_SE',-29.10000000,26.30000000), ('OUT_NE',29.00000000,127.00000000), ('OUT_NW',30.00000000,-120.00000000), ('OUT_SE',-45.00000000,130.00000000), ('OUT_SW',-40.00000000,-45.00000000);
查询语句
SELECT f.Place, f.Lat, f.Lon FROM tempdata.sample f WHERE ST_Contains(ST_GeomFromText('POLYGON(( 20.92061458693626 -42.957921556353014, 8.551680010173861 -30.52917617616417, 21.9325174415095 -19.051246698460766, 28.12566921079717 -16.967667823403218, 38.428497878482574 -27.255151898241817, 35.35015222665547 -32.90654636609105, 20.92061458693626 -42.957921556353014))', 4326), ST_GeomFromText(CONCAT('POINT(', f.lon, ' ', f.lat, ')'), 4326));
技术解释与解决方案
WKT规范与坐标顺序
WKT(Well-Known Text)规范中的坐标顺序并非固定为"经度在前、纬度在后",而是由空间参考系统(SRS)的定义决定。
对于常用的EPSG:4326(WGS84地理坐标系),MySQL 8.0开始严格遵循OGC(开放地理空间联盟)规范:在地理坐标系中,坐标顺序为纬度(y轴,南北方向)在前,经度(x轴,东西方向)在后。这和很多人直觉中的顺序相反,但符合OGC对地理坐标系轴顺序的定义。
MySQL 5.6对坐标顺序的校验较为宽松,即使传入"经度在前"的坐标也不会报错(但可能存在隐性计算错误);而MySQL 8.0新增了严格的坐标范围校验,当你把超过纬度范围(-90~90)的经度值放在第一个位置时,系统会将其识别为纬度,从而触发3617错误——比如测试数据中OUT_NE的经度127,就被当作纬度校验,自然超出范围。
可行解决方案
方案1:调整坐标顺序(遵循OGC规范)
将POINT和POLYGON的WKT坐标改为纬度在前、经度在后的格式:
- 查询中的POINT构造语句改为:
CONCAT('POINT(', f.lat, ' ', f.lon, ')') - POLYGON中的坐标也对应调整为
纬度 经度的顺序,例如原坐标20.92061458693626 -42.957921556353014改为-42.957921556353014 20.92061458693626
方案2:显式指定轴顺序(兼容原有习惯)
MySQL 8.0的ST_GeomFromText支持第三个参数axis-order,可以直接指定坐标顺序为longitude-first(经度在前),无需修改坐标字符串:
SELECT f.Place, f.Lat, f.Lon FROM tempdata.sample f WHERE ST_Contains( ST_GeomFromText('POLYGON(( 20.92061458693626 -42.957921556353014, 8.551680010173861 -30.52917617616417, 21.9325174415095 -19.051246698460766, 28.12566921079717 -16.967667823403218, 38.428497878482574 -27.255151898241817, 35.35015222665547 -32.90654636609105, 20.92061458693626 -42.957921556353014))', 4326, 'longitude-first'), ST_GeomFromText(CONCAT('POINT(', f.lon, ' ', f.lat, ')'), 4326, 'longitude-first') );
注意事项
- 若选择调整坐标顺序,需确保所有空间数据(表中存储、查询构造的)统一使用纬度在前的格式,避免后续空间计算出错。
- 从长远兼容性考虑,建议遵循OGC规范和MySQL 8.0的默认行为,采用纬度在前的坐标顺序,减少跨系统、跨版本的适配成本。
内容的提问来源于stack exchange,提问作者Lefty

