HQL分组聚合查询求助:非聚合字段处理及子查询实现
解决HQL分组时返回非聚合字段的问题
情况1:p.t3、p.t5与p.t6是一一对应关系
如果业务逻辑里同一个p.t6值对应的p.t3和p.t5是唯一的,直接把这两个字段加入GROUP BY子句即可。HQL仅要求所有非聚合字段必须出现在分组条件中,这种操作不会影响聚合结果:
@Query("SELECT new value.Value " + "(SUM(p.t1), SUM(p.t2), p.t3, SUM(p.t4), p.t5, p.t6) " + "FROM P p " + "WHERE p.tId = :tId " + "GROUP BY p.t6, p.t3, p.t5")
情况2:同一个p.t6下存在多个不同的p.t3/p.t5值
如果同一个t6分组下有多个不同的t3或t5,你需要先明确要返回该分组下的哪一个值(比如第一条记录的、最大值、最小值等),以下是两种可行实现方式:
方式A:子查询先算聚合,再关联主表取字段
先通过子查询算出每个t6对应的聚合结果,再关联原表获取对应的t3和t5(示例取分组内任意一条记录的t3/t5,可按需调整关联条件):
@Query("SELECT new value.Value " + "(agg.sumT1, agg.sumT2, p.t3, agg.sumT4, p.t5, agg.t6) " + "FROM (SELECT SUM(t1) as sumT1, SUM(t2) as sumT2, SUM(t4) as sumT4, t6 " + "FROM P " + "WHERE tId = :tId " + "GROUP BY t6) agg " + "JOIN P p ON agg.t6 = p.t6 AND p.tId = :tId " + "GROUP BY agg.sumT1, agg.sumT2, p.t3, agg.sumT4, p.t5, agg.t6")
方式B:使用窗口函数(Hibernate 5.2+支持)
如果你的Hibernate版本支持窗口函数,可借助ROW_NUMBER()标记分组内的第一条记录,再筛选出该记录并携带聚合值:
@Query("SELECT new value.Value " + "(sumT1, sumT2, t3, sumT4, t5, t6) " + "FROM (SELECT SUM(p.t1) OVER (PARTITION BY p.t6) as sumT1, " + "SUM(p.t2) OVER (PARTITION BY p.t6) as sumT2, " + "p.t3, " + "SUM(p.t4) OVER (PARTITION BY p.t6) as sumT4, " + "p.t5, " + "p.t6, " + "ROW_NUMBER() OVER (PARTITION BY p.t6 ORDER BY p.id) as rn " + "FROM P p " + "WHERE p.tId = :tId) sub " + "WHERE sub.rn = 1")
关键说明
HQL严格遵循SQL标准,要求所有出现在SELECT中的非聚合字段必须存在于GROUP BY子句中,这和PostgreSQL的宽松模式不同。你需要根据业务逻辑中t3、t5和t6的关联关系选择合适方案:如果是一一对应,直接加GROUP BY最简洁;如果存在多值,必须明确取值规则后再实现。
内容的提问来源于stack exchange,提问作者Marzepanio Tortus
相关产品推荐
相关产品推荐

