You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 06:06:04