Grails中使用Sql executeUpdate预编译语句实现IN查询(含数组参数)的报错解决方法
解决PostgreSQL中预编译语句IN()查询的类型不匹配问题
你遇到的org.postgresql.util.PSQLException: ERROR: operator does not exist: bigint = bigint[]错误,本质是因为PostgreSQL把你传入的long[]数组当成了数据库数组类型,但IN()子句需要的是逗号分隔的单个值列表,不是数组类型,所以数据库找不到对应的匹配操作符。
下面给你几种可行的解决方案,你可以根据自己的代码场景选择:
方案1:手动生成占位符(通用JDBC预编译写法)
这种方法是最通用的,适用于所有JDBC兼容的框架。核心思路是根据数组长度生成对应数量的?占位符,然后把数组元素展开作为参数传入:
long[] test = [1,2] // 根据数组长度生成多个?占位符,比如数组长度为2就生成"?,?" def placeholders = test.collect { '?' }.join(',') // 执行更新操作 sql.executeUpdate( "UPDATE outbound_message set acknowledged = true, acknowledged_date = NOW(), acknowledged_from = ? where id in($placeholders) and acknowledged = false", // 参数列表:先放用户名,再放数组的所有元素 [userNameToUse] + test.toList() )
这样预编译语句会把每个数组元素当成独立的bigint参数,完美匹配id字段的类型,不会再出现类型不匹配的问题。
方案2:利用PostgreSQL的数组操作符= ANY()
PostgreSQL支持直接对数组进行包含查询,你可以用= ANY()替代IN(),同时显式转换参数类型来适配:
long[] test = [1,2] sql.executeUpdate( "UPDATE outbound_message set acknowledged = true, acknowledged_date = NOW(), acknowledged_from = :user where id = ANY(:list::bigint[]) and acknowledged = false", [user: userNameToUse, list: test] )
这里的::bigint[]是PostgreSQL的类型转换语法,把传入的数组参数显式转换成bigint数组类型,数据库就能正确识别并匹配id字段了。这种写法更简洁,不需要手动生成占位符。
方案3:如果用Groovy GORM(Grails项目)
如果你的代码是基于Grails的GORM实现,那么可以直接用GORM的inList方法,它会自动帮你处理预编译和参数绑定:
OutboundMessage.where { id inList test acknowledged == false }.updateAll( acknowledged: true, acknowledgedDate: new Date(), acknowledgedFrom: userNameToUse )
这种写法完全不需要手动写SQL,代码可读性更高,也避免了类型匹配的问题。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

