基于经纬度的地址及距离检索JPQL查询报错,请求修正
修复Spring Data JPA地理距离查询的Having子句错误
你猜的没错,问题确实出在HQL对别名的解析规则以及having子句的使用场景上。咱们一步步来解决:
错误根源
having的使用场景不对:having是用来过滤分组后的结果,必须配合group by一起使用,你这里没有分组操作,直接用having本身就违反了HQL语法。- 别名无法在
having中引用:即使有分组,HQL解析器也不允许在having里直接引用select子句中定义的别名(比如你这里的distance),因为解析顺序是先处理where/having,再处理select的别名绑定。
修正方案一:用where替代having,重复距离计算表达式
既然不需要分组,直接用where子句过滤,把距离计算的逻辑完整复制到where里就行:
@Query("Select new com.geolocation.AddressVM(A, " + "(" + " 6371 * " + " acos( " + " cos(radians(:lat)) * " + " cos(radians(A.geoLocation.latitude)) *" + " cos(" + " radians(A.geoLocation.longtitude) - radians(:lng)" + " ) + " + " sin(radians(:lat)) *" + " sin(radians(A.geoLocation.latitude))" + " ) " + ") as distance) " + "from #{#entityName} A " + "where (" + " 6371 * " + " acos( " + " cos(radians(:lat)) * " + " cos(radians(A.geoLocation.latitude)) *" + " cos(" + " radians(A.geoLocation.longtitude) - radians(:lng)" + " ) + " + " sin(radians(:lat)) *" + " sin(radians(A.geoLocation.latitude))" + " ) " + ") > :distance") List<AddressVM> list(@Param("lat") double lat, @Param("lng") double lng, @Param("distance") double distance);
修正方案二:使用子查询(更简洁,避免重复代码)
把计算距离的逻辑放到子查询里,外层再过滤结果,这样代码更易读:
@Query("Select addrWithDistance from (" + " Select new com.geolocation.AddressVM(A, " + " (" + " 6371 * " + " acos( " + " cos(radians(:lat)) * " + " cos(radians(A.geoLocation.latitude)) *" + " cos(" + " radians(A.geoLocation.longtitude) - radians(:lng)" + " ) + " + " sin(radians(:lat)) *" + " sin(radians(A.geoLocation.latitude))" + " ) " + ") as distance) " + "from #{#entityName} A) addrWithDistance " + "where addrWithDistance.distance > :distance") List<AddressVM> list(@Param("lat") double lat, @Param("lng") double lng, @Param("distance") double distance);
额外提示
- 确保你的
AddressVM有对应的构造器:public AddressVM(Address entity, double distance),否则映射会失败。 - 如果你的数据库支持地理空间函数(比如PostGIS、MySQL的ST_Distance),可以考虑用原生SQL或者数据库自带的地理函数,性能会比手动计算Haversine公式更好。
内容的提问来源于stack exchange,提问作者dkn
相关产品推荐
相关产品推荐

