聚集查询中使用GROUP BY返回主键且不纳入分组的HQL实现咨询
首先直接给结论:你提供的原HQL语句在绝大多数场景下不符合SQL(及HQL)规范,执行会报错。因为SQL标准明确要求:SELECT列表里未被聚合函数包裹的列,必须全部出现在GROUP BY子句中。你的主键fichaProc.ID不在分组条件里时,数据库无法确定要返回同一procedimento.id分组下的哪一个ID——毕竟同一个分组可能对应多条不同主键的记录。
不过根据你的业务需求,有几种合规且实用的解决办法:
1. 用聚合函数包裹主键ID
如果你只需要分组内任意一个主键(比如取最大、最小的ID),可以用MAX()或MIN()这类聚合函数把主键包起来,这样就完全符合规范了:
select max(fichaProc.ID), fichaProc.procedimento.id, sum(fichaProc.qtd), sum(fichaProc.valorProc) from XXX group by fichaProc.procedimento.id
这种写法跨数据库兼容,结果也可预期——返回的是该分组里主键最大(或最小)的那条记录的ID,在很多业务场景下都能满足需求。
2. 若业务是一对一关联,直接把主键加入GROUP BY
如果fichaProc.procedimento.id和fichaProc.ID是一对一关系(即每个procedimento.id只对应一条fichaProc记录),那把主键加入GROUP BY完全不会改变分组逻辑,同时符合规范:
select fichaProc.ID, fichaProc.procedimento.id, sum(fichaProc.qtd), sum(fichaProc.valorProc) from XXX group by fichaProc.ID, fichaProc.procedimento.id
因为一对一关联下,每个fichaProc.ID对应唯一的procedimento.id,分组结果和你原本的预期完全一致,只是多了一个合法的分组键而已。
3. 不推荐:依赖数据库非标准扩展
有些数据库(比如MySQL关闭ONLY_FULL_GROUP_BY模式时)允许这种不符合规范的写法,但强烈不建议这么做。一来HQL作为跨数据库查询语言,依赖这种扩展会导致代码无法在其他数据库运行;二来返回的主键是随机的,结果不可预测,很容易引发业务问题。
总结一下:优先选择前两种方案,确保查询合规、结果可预期。
内容的提问来源于stack exchange,提问作者nori

