使用Diesel.rs时SELECT MAX与其他字段报错的问题排查与解决
问题原因
Diesel作为严格遵循SQL标准的ORM,会强制校验GROUP BY查询的合法性:当使用GROUP BY分组后,SELECT子句中的列必须满足两个条件之一——要么是GROUP BY中明确指定的分组列,要么是被聚合函数(比如MAX、MIN)包裹的列。
你的查询中,GROUP BY仅指定了progress::otherid,但SELECT里包含了progress::onemoreid,它既不是分组列,也没有被聚合函数处理,这种混合聚合与非分组/非聚合列的写法违反了SQL标准,因此Diesel抛出了MixedAggregates trait未实现的错误。当你移除progress::onemoreid时,SELECT里只有聚合函数和分组列,符合规则,所以错误消失。
修复方案
根据你的业务需求选择以下两种方案之一:
方案1:将onemoreid加入GROUP BY(适用于每个otherid分组对应唯一onemoreid的场景)
如果onemoreid在同一个otherid分组中是唯一的(比如两者是联合主键),直接把它添加到GROUP BY子句中,让查询符合SQL标准:
let sub = progress::table .filter(progress::user.eq(1)) .group_by((progress::otherid, progress::onemoreid)) // 新增onemoreid到分组 .select((diesel::dsl::max(progress::updated), progress::otherid, progress::onemoreid));
对应的SQL会变为:
SELECT otherid, onemoreid, MAX(updated) AS newest_updated FROM progress WHERE user = 1 GROUP BY otherid, onemoreid
方案2:对onemoreid使用聚合函数(适用于同一个otherid分组有多个onemoreid的场景)
如果同一个otherid分组下存在多个onemoreid值,你需要用聚合函数指定如何选取该列的值。比如使用MySQL特有的ANY_VALUE函数(用于任意选取分组内的一个值),或者MAX/MIN等通用聚合函数:
使用ANY_VALUE(MySQL专属)
use diesel::dsl::any_value; let sub = progress::table .filter(progress::user.eq(1)) .group_by(progress::otherid) .select((diesel::dsl::max(progress::updated), progress::otherid, any_value(progress::onemoreid)));
对应的SQL:
SELECT otherid, ANY_VALUE(onemoreid), MAX(updated) AS newest_updated FROM progress WHERE user = 1 GROUP BY otherid
使用MAX/MIN(通用SQL标准)
如果需要选取分组内onemoreid的最大值或最小值:
let sub = progress::table .filter(progress::user.eq(1)) .group_by(progress::otherid) .select((diesel::dsl::max(progress::updated), progress::otherid, diesel::dsl::max(progress::onemoreid)));
内容的提问来源于stack exchange,提问作者filif96770
相关产品推荐
相关产品推荐

