Spring @Query如何实现Postgres按每N分钟分组统计字段平均值
PostgreSQL按时间间隔分组统计@Query实现
直接使用原生SQL模式实现,无需适配JPQL语法,同时支持动态传入分组分钟间隔,代码可直接复用。
核心Repository代码
import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import java.time.LocalDateTime; import java.util.List; import java.math.BigDecimal; public interface PriceRepository extends CrudRepository<PriceRecord, Long> { @Query(value = "SELECT AVG(price) AS price, " + "date_trunc('hour', created) + (date_part('minute', created)::int / :intervalMinutes) * make_interval(mins => :intervalMinutes) AS created " + "FROM table_name " + "WHERE created BETWEEN :startTime AND :endTime " + "GROUP BY created " + "ORDER BY created ASC", nativeQuery = true) List<PriceStat> getAvgPriceByTimeInterval( @Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, @Param("intervalMinutes") Integer intervalMinutes ); // 结果投影接口,Spring会自动映射查询结果 interface PriceStat { BigDecimal getPrice(); LocalDateTime getCreated(); } }
实现说明
- 开启
nativeQuery = true直接执行原生PostgreSQL语句,完全兼容原SQL的::int类型转换、时间运算逻辑,不需要用JPQL的function()做繁琐的函数适配,避免类型转换报错。 - 动态间隔通过PostgreSQL内置
make_interval()函数实现,替代原SQL中硬编码的interval '5 min',传入任意正整数分钟值即可切换分组粒度,无需修改SQL语句。 - 时间参数直接使用
LocalDateTime类型传递,不需要手动拼接时间字符串,避免时区、格式不匹配问题;均价用BigDecimal接收,保证浮点计算精度。
结果验证
传入参数startTime=2022-04-19T00:00:00、endTime=2022-04-19T23:59:00、intervalMinutes=5,基于提供的测试数据返回结果完全符合预期:
- 00:00:00时间点对应0-5分钟区间(不含第5分钟),均价为(100+107+109)/3 ≈ 105.33
- 00:05:00时间点对应5-10分钟区间(不含第10分钟),均价为(105+97+99)/3 ≈ 100.33
若使用JDK15及以上版本,可将SQL字符串替换为Java文本块(
"""...""")简化代码书写,逻辑无变化。
内容的提问来源于stack exchange,提问作者handle2
相关产品推荐
相关产品推荐

