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

Hibernate Criteria如何实现含max()函数的多列子查询

将指定SQL转换为Hibernate Criteria查询

原SQL逻辑

原SQL通过子查询获取每个ueb_uuid对应的最大version,再关联主表筛选出每个ueb_uuid的最新版本数据:

SELECT
    a.*
FROM
    objekt a,
    -- Filter on max version 
    (
        SELECT
            ueb_uuid,
            MAX(version) AS version
        FROM
            objekt
        GROUP BY
            ueb_uuid
    ) b
WHERE
        a.version = b.version
    AND a.ueb_uuid = b.ueb_uuid;

问题分析

核心难点是子查询需要同时返回两种不同类型的列(ueb_uuid和MAX(version)),而非单一值,以此关联主表完成筛选。

你的尝试代码

Subquery<Integer> subquery = query.subquery(Integer.class);
Root<ObjektEntity> subqueryRoot =   subquery.from(ObjektEntity.class);
    
subquery.select(builder.max(subqueryRoot.get(ObjektEntity_.version)));
    
subquery.where(builder.equal(root.get(AnotherEntity_.objekt),objekt.get(ObjektEntity_.uuid) )); 
     
query.where(builder.equal(root.get(ObjektEntity_.VERSION),subquery));

解决方案

使用Tuple作为子查询的返回类型,同时承载ueb_uuid和最大版本号,再通过多条件关联主表:

CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<ObjektEntity> criteriaQuery = builder.createQuery(ObjektEntity.class);
Root<ObjektEntity> root = criteriaQuery.from(ObjektEntity.class);

// 构建子查询,返回包含ueb_uuid和max(version)的Tuple
Subquery<Tuple> subquery = criteriaQuery.subquery(Tuple.class);
Root<ObjektEntity> subRoot = subquery.from(ObjektEntity.class);

// 子查询选择目标字段并分组
subquery.select(builder.tuple(
    subRoot.get(ObjektEntity_.ueb_uuid),
    builder.max(subRoot.get(ObjektEntity_.version))
));
subquery.groupBy(subRoot.get(ObjektEntity_.ueb_uuid));

// 主查询通过两个条件关联子查询,匹配ueb_uuid和对应最大版本
criteriaQuery.where(builder.and(
    builder.equal(root.get(ObjektEntity_.ueb_uuid), subRoot.get(ObjektEntity_.ueb_uuid)),
    builder.equal(root.get(ObjektEntity_.version), builder.max(subRoot.get(ObjektEntity_.version)))
));

// 执行查询获取结果
List<ObjektEntity> latestVersionEntities = session.createQuery(criteriaQuery).getResultList();

关键说明

  1. 子查询返回类型:用Tuple可以灵活承载多列不同类型的数据,适配ueb_uuid(如UUID/String)和version(Integer)的类型差异
  2. 多字段关联:通过builder.and()组合两个等式,完全对齐原SQL中主表与子查询的关联逻辑
  3. 分组逻辑:子查询通过groupBy(subRoot.get(ObjektEntity_.ueb_uuid))实现原SQL的分组取最大版本逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 05:15:33