Java11+Postgres9.6使用CASE WHEN传参报类型错误如何解决?
错误原因
你遇到的报错:
PSQLException: ERROR: argument of CASE/WHEN must be type boolean, not type record
根本原因是PostgreSQL对CASE语句内的参数类型推断规则和普通WHERE子句不同:当你绑定的:designatorInclude是集合类型(列表/数组)时,PostgreSQL在解析WHEN (:designatorInclude IS NOT NULL)这段逻辑时,会将集合参数识别为多行记录(record)类型,无法直接返回标量布尔值,进而触发类型不匹配错误。你之前在非CASE场景下可以正常使用,是因为普通WHERE子句对IN集合参数的类型推断优先级更高,不会出现类型识别偏差。
可行解决方案
方案1:替换CASE为WHERE逻辑组合(推荐,改造成本最低)
直接去掉CASE语句,用OR组合两段条件,完全避开CASE的类型推断问题,改造后的WHERE片段如下:
WHERE COALESCE(ll.location_id, cl.location_id) = :locationId AND ll.do_not_list_on_markets = false AND ( (:designatorInclude IS NOT NULL AND totdl.designator_id IN (:designatorInclude)) OR (:designatorInclude IS NULL AND ttl.product_code IS NOT NULL) )
该方案不需要修改任何Java代码,仅调整SQL即可,和原有逻辑完全等价。
方案2:明确集合参数类型,使用ANY替代IN
如果必须保留CASE结构,可以将IN子句替换为PostgreSQL原生支持的ANY表达式,明确指定参数为数组类型,避免类型推断错误:
首先调整Java侧代码,将传入的列表转换为JDBC兼容的数组类型:
if(inDto.getIdList() != null && !inDto.getIdList().isEmpty()) { // 假设designator_id是Integer类型,按需调整数组类型 Array idArray = em.unwrap(Connection.class).createArrayOf("int4", inDto.getIdList().toArray()); filterProductCodesQuery.setParameter("designatorInclude", idArray); } else { filterProductCodesQuery.setParameter("designatorInclude", null); }
然后修改SQL的CASE片段:
AND CASE WHEN (:designatorInclude IS NOT NULL) THEN totdl.designator_id = ANY(:designatorInclude) ELSE ttl.product_code IS NOT NULL END
方案3:Java侧动态拼接SQL
如果项目允许使用动态SQL,可以在Java侧判断参数是否为空,直接拼接对应的WHERE条件,完全避免运行时参数类型判断的问题,执行效率也更高。
内容的提问来源于stack exchange,提问作者TylerTwoForks
相关产品推荐
相关产品推荐

