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

如何将含左连接、子查询、GROUP BY的SQL转换为JPA CriteriaBuilder查询

SQL转JPA CriteriaBuilder实现方案

前提说明

  • 先完成实体类映射:Candidate实体对应candy.candidate表,JCandidateJobProfile实体对应candy.j_candidate_job_profile表,所有字段映射规则与数据库一致
  • 以下实现基于JPA 2.1及以上版本,核心逻辑完全对齐提供的原生SQL

完整实现代码

import javax.persistence.criteria.*;
import javax.persistence.Tuple;
import java.util.List;

// 此处entityManager为Spring注入/自行初始化的JPA EntityManager实例
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
// 定义返回结果为Object[],下标0为Candidate对象,下标1为最大得分
CriteriaQuery<Object[]> mainQuery = cb.createQuery(Object[].class);
Root<Candidate> candiRoot = mainQuery.from(Candidate.class);

// 1. 构造子查询,对应原生SQL中的ponderation临时表
Subquery<Tuple> ponderationSub = mainQuery.subquery(Tuple.class);
Root<JCandidateJobProfile> jobProfileRoot = ponderationSub.from(JCandidateJobProfile.class);

// 实现CASE WHEN得分计算逻辑
Expression<Integer> scoreCalculation = cb.selectCase()
        .when(
            cb.and(
                cb.equal(jobProfileRoot.get("profileId"), 941),
                cb.equal(jobProfileRoot.get("skillTypeId"), 970)
            ), 10
        )
        .when(
            cb.and(
                cb.equal(jobProfileRoot.get("profileId"), 941),
                cb.equal(jobProfileRoot.get("skillTypeId"), 972)
            ), 3
        )
        .otherwise(cb.nullLiteral(Integer.class));

// 子查询返回字段:候选人ID、计算后的得分
ponderationSub.multiselect(
        jobProfileRoot.get("candidateId").alias("candidate_id"),
        scoreCalculation.alias("score")
);

// 2. 实现LEFT JOIN子查询,关联条件为候选人ID相等
Join<Candidate, Tuple> ponderationJoin = candiRoot.join(
        ponderationSub,
        JoinType.LEFT,
        cb.equal(candiRoot.get("id"), ponderationSub.get("candidate_id"))
);

// 3. 设置WHERE条件:过滤得分不为空的记录
mainQuery.where(cb.isNotNull(ponderationJoin.get("score")));

// 4. 实现GROUP BY与MAX聚合
Expression<Integer> maxScoreExp = cb.max(ponderationJoin.get("score").as(Integer.class));
mainQuery.multiselect(candiRoot, maxScoreExp.alias("score"));
mainQuery.groupBy(candiRoot.get("id"));

// 5. 按候选人ID升序排序
mainQuery.orderBy(cb.asc(candiRoot.get("id")));

// 执行查询获取结果
List<Object[]> result = entityManager.createQuery(mainQuery).getResultList();

低版本JPA兼容说明

如果使用的JPA版本低于2.1,不支持直接JOIN子查询,可以调整逻辑为:先查询所有符合得分规则的JCandidateJobProfile记录的候选人ID和最高得分,再关联Candidate表查询匹配的候选人信息即可。

内容的提问来源于stack exchange,提问作者Mohamed El-Harrougui

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 10:27:03