如何在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
相关产品推荐
相关产品推荐

