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

如何在QueryDSL与Spring Boot JPA中编写Group By查询获取最新版本记录

解决方案:按type+number分组获取最新version记录

你的核心需求是按type和number分组,获取每组中version最大的完整记录,之前的尝试问题在于没有正确关联分组后的最大version与原表记录,以下是几种可行的实现方式:

方式一:QueryDSL子查询关联(推荐)

利用子查询针对每条记录匹配同组的最大version,直接筛选出符合条件的完整记录:

QRecord record = QRecord.record;
QRecord subRecord = new QRecord("subRecord"); // 子查询表别名

// 子查询:获取当前record同type同number的最大version
JPASubQuery<Long> maxVersionSubQuery = JPAExpressions.select(subRecord.version.max())
    .from(subRecord)
    .where(subRecord.type.eq(record.type)
        .and(subRecord.number.eq(record.number)));

// 主查询:筛选指定type下,version等于同组最大值的记录
List<Record> newestRecords = queryFactory.selectFrom(record)
    .where(record.type.eq(targetType) // 替换为你的目标type参数
        .and(record.version.eq(maxVersionSubQuery)))
    .fetch()
    .stream()
    .map(RecordMapper::mapRecord)
    .collect(Collectors.toList());

方式二:分组后关联查询

先分组得到每组的最大version,再通过条件筛选原表记录:

QRecord record = QRecord.record;

// 第一步:获取指定type下,每个(number)对应的最大version
List<Tuple> maxVersionTuples = queryFactory.select(record.type, record.number, record.version.max())
    .from(record)
    .where(record.type.eq(targetType))
    .groupBy(record.type, record.number)
    .fetch();

// 第二步:构建条件,匹配所有(type, number, maxVersion)组合
BooleanBuilder filterBuilder = new BooleanBuilder();
for (Tuple tuple : maxVersionTuples) {
    Long type = tuple.get(record.type);
    Long number = tuple.get(record.number);
    Long maxVersion = tuple.get(record.version.max());
    
    filterBuilder.or(record.type.eq(type)
        .and(record.number.eq(number))
        .and(record.version.eq(maxVersion)));
}

// 查询完整记录
List<Record> newestRecords = queryFactory.selectFrom(record)
    .where(filterBuilder)
    .fetch()
    .stream()
    .map(RecordMapper::mapRecord)
    .collect(Collectors.toList());

方式三:JPA原生SQL查询

如果QueryDSL写法复杂,也可以直接用原生SQL实现,性能更直观:

@Repository
public interface RecordRepository extends JpaRepository<Record, Long> {

    @Query(value = "SELECT r.* FROM record r " +
                   "INNER JOIN (" +
                   "    SELECT type, number, MAX(version) AS max_version " +
                   "    FROM record " +
                   "    WHERE type = :targetType " +
                   "    GROUP BY type, number" +
                   ") sub ON r.type = sub.type " +
                   "AND r.number = sub.number " +
                   "AND r.version = sub.max_version",
           nativeQuery = true)
    List<Record> findLatestRecordsByType(@Param("targetType") Long targetType);
}

关键说明

之前的尝试错误在于:

  • 全局取MAX(version)而不是按type+number分组取MAX,导致只能拿到全表最新的一条,而非每组最新
  • 分组后没有关联回原表获取完整记录,只拿到了分组的聚合结果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 20:30:57