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

如何在JPA查询中实现参数非空时使用IN子句?使用:ramos is null判断触发ORA-00920无效关系运算符错误

解决JPA查询中集合参数的IN子句动态判断问题

我刚帮你排查了这个问题,你遇到的ORA-00920: invalid relational operator错误,核心原因是不能直接用is null判断List类型的参数——JPA对集合参数的解析逻辑和普通字符串/数值参数不一样,直接写:ramos is null会生成无效的SQL语法。

下面给你两种实用的解决方案,按需选择:

方案一:使用SpEL表达式判断集合是否为空(最简单)

Spring Data JPA支持SpEL表达式,你可以用:ramos is empty来判断集合是否为空,如果要覆盖参数为null的场景,还可以加上:ramos is null。修改后的查询代码如下:

@Query(value = "SELECT r FROM ParceiroNegocio r " + 
        " WHERE (:razaoSocial is null or UPPER(r.razaoSocial) LIKE CONCAT('%',UPPER(:razaoSocial),'%')) " + 
        " AND (:nomeFantasia is null or UPPER(r.nomeFantasia) LIKE CONCAT('%',UPPER(:nomeFantasia),'%')) " + 
        " AND (:cnpj is null or r.cnpj =:cnpj) " + 
        " AND ((:ramos is null or :ramos is empty) or r.ramo IN (:ramos))")
Page<ParceiroNegocio> findByCnpjNomeFantasiaRazaoSocialRamoWithPagination(
    @Param("razaoSocial") String razaoSocial,
    @Param("nomeFantasia") String nomeFantasia,
    @Param("cnpj") String cnpj,
    @Param("ramos") List<Long> ramos,
    Pageable pageable);

逻辑说明:

  • 当ramos为null或空集合时,(:ramos is null or :ramos is empty)为true,整个AND分支直接成立,不会触发IN子句;
  • 当ramos有元素时,才会执行r.ramo IN (:ramos)的判断。

方案二:使用动态查询(更灵活,适合多条件场景)

如果你的查询条件经常变化,或者想避免在@Query里写复杂的条件拼接,推荐用Spring Data JPA的Specification来实现动态查询:

第一步:定义Specification类

public class ParceiroNegocioSpecifications {
    public static Specification<ParceiroNegocio> filterByParams(String razaoSocial, String nomeFantasia, String cnpj, List<Long> ramos) {
        return (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 处理razaoSocial模糊查询
            if (razaoSocial != null && !razaoSocial.isBlank()) {
                predicates.add(criteriaBuilder.like(
                    criteriaBuilder.upper(root.get("razaoSocial")),
                    "%" + razaoSocial.toUpperCase() + "%"
                ));
            }
            
            // 处理nomeFantasia模糊查询
            if (nomeFantasia != null && !nomeFantasia.isBlank()) {
                predicates.add(criteriaBuilder.like(
                    criteriaBuilder.upper(root.get("nomeFantasia")),
                    "%" + nomeFantasia.toUpperCase() + "%"
                ));
            }
            
            // 处理cnpj精确匹配
            if (cnpj != null && !cnpj.isBlank()) {
                predicates.add(criteriaBuilder.equal(root.get("cnpj"), cnpj));
            }
            
            // 处理ramos的IN判断
            if (ramos != null && !ramos.isEmpty()) {
                predicates.add(root.get("ramo").in(ramos));
            }
            
            // 拼接所有条件
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };
    }
}

第二步:修改Repository接口

让你的Repository继承JpaSpecificationExecutor<ParceiroNegocio>:

public interface ParceiroNegocioRepository extends JpaRepository<ParceiroNegocio, Long>, JpaSpecificationExecutor<ParceiroNegocio> {
    // 这里可以删掉原来的@Query方法,用动态查询替代
}

第三步:调用查询

// 在业务代码中调用
Page<ParceiroNegocio> parceiroPage = parceiroNegocioRepository.findAll(
    ParceiroNegocioSpecifications.filterByParams(razaoSocial, nomeFantasia, cnpj, ramos),
    pageable
);

这种方式的好处是逻辑更清晰,能精准控制每个条件是否加入查询,完全避免了SQL语法错误的风险。

内容的提问来源于stack exchange,提问作者Diogo Zucchi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 20:14:05