MySQL使用ST_Contains查询空间数据时SRID不匹配报错如何解决
问题根因
你遇到的SRID不匹配问题核心原因有两点:
districts表的bounding_box字段实际存储的几何数据SRID为0,和查询时点坐标的SRID 4326不一致- 你通过
ST_GeomFromGeoJSON生成的几何数据默认SRID为4326,但存入数据库后变为0,大概率是创建表时没有为bounding_box字段显式指定SRID为4326:- MySQL默认几何类型字段的SRID为0,存入数据时会自动将几何值的SRID覆盖为字段设置的SRID
- Laravel默认生成空间字段的迁移时,如果没有传入SRID参数,默认也会使用SRID 0
- 你之前调用
ST_Transform报错是因为SRID 0代表未知空间参考系,MySQL不支持从SRID 0做坐标系转换。
最优解决方案(推荐)
该方案可以保证地理计算精度,一劳永逸解决问题:
步骤1:修正表字段SRID设置
如果用原生SQL修改表,执行以下语句(字段类型根据你的实际存储调整,多边形用POLYGON,多多边形用MULTIPOLYGON):
ALTER TABLE districts MODIFY COLUMN bounding_box POLYGON SRID 4326 NOT NULL;
如果是Laravel迁移,字段定义改为:
$table->polygon('bounding_box', 4326); // 第二个参数为指定SRID
步骤2:重新导入边界数据
重新通过ST_GeomFromGeoJSON解析GeoJSON数据存入bounding_box字段,此时存储的几何数据SRID会保留为4326。
步骤3:执行查询
注意ST_Contains参数顺序:ST_Contains(外包围几何, 被包含几何),要查询包含目标点的区县,应该将bounding_box作为第一个参数:
SELECT id, bounding_box FROM `districts` WHERE ST_Contains(bounding_box, ST_GeomFromText('Point(-96.505144 41.322207)', 4326))
如果用ST_Within,参数顺序反过来即可,SRID统一的前提下不会报错:
SELECT id, bounding_box FROM `districts` WHERE ST_Within(ST_GeomFromText('Point(-96.505144 41.322207)', 4326), bounding_box)
临时兼容方案(不修改现有数据)
如果暂时无法修改表结构和重新导入数据,可以统一查询时两边的SRID为0,直接去掉点坐标的SRID参数即可:
SELECT id, bounding_box FROM `districts` WHERE ST_Contains(bounding_box, ST_GeomFromText('Point(-96.505144 41.322207)'))
注意:该方案使用平面坐标计算,地理距离、范围判断的精度会有明显偏差,仅适合临时测试使用
Laravel中调用示例
// 按最优方案的查询写法 $point = 'Point(-96.505144 41.322207)'; $districts = \App\Models\District::whereRaw( "ST_Contains(bounding_box, ST_GeomFromText(?, 4326))", [$point] )->get();
内容的提问来源于stack exchange,提问作者Nict
相关产品推荐
相关产品推荐

