Rust Diesel 1.4.8编写group by查询报NonAggregate错误如何修复
问题描述
使用Rust Diesel 1.4.8版本编写分组查询时遇到编译错误,项目依赖配置如下:
diesel = { version = "1.4.8", features = ["postgres","64-column-tables","chrono","serde_json"] }
最初编写的分组查询代码如下:
fpub fn get_bill_book_account_sum(){ use crate::diesel::GroupByDsl; use diesel::dsl::max; use crate::model::diesel::dict::dict_schema::test as bill_record_table; let source_query = bill_record_table::table .group_by(bill_record_table::id) .select((max(bill_record_table::tags),bill_record_table::id)) .filter(bill_record_table::dsl::tags.eq(9)); }
编译时抛出如下错误:
error[E0277]: the trait bound `aggregate_ordering::max::max<BigInt, columns::tags>: NonAggregate` is not satisfied --> src/main.rs:19:17 | 19 | .select((max(bill_record_table::tags),bill_record_table::id)) | ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonAggregate` is not implemented for `aggregate_ordering::max::max<BigInt, columns::tags>` | | | required by a bound introduced by this call | = note: required because of the requirements on the impl of `diesel::Expression` for `(aggregate_ordering::max::max<BigInt, columns::tags>, columns::id)` note: required by a bound in `diesel::QueryDsl::select` --> /Users/xiaoqiangjiang/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd/diesel-1.4.8/src/query_dsl/mod.rs:291:20 | 291 | Selection: Expression, | ^^^^^^^^^^ required by this bound in `diesel::QueryDsl::select` For more information about this error, try `rustc --explain E0277`. error: could not compile `rust-learn` due to previous error
用于构造最小复现示例的相关代码如下:
- 表schema定义:
table! { test (id) { id -> Int8, tags -> Int8, } }
- 对应模型定义:
// Generated by diesel_ext #![allow(unused)] #![allow(clippy::all)] use std::io::Write; use diesel::deserialize::FromSql; use diesel::pg::Pg; use diesel::serialize::{Output, ToSql}; use diesel::sql_types::Jsonb; use rocket::serde::Serialize; use serde::Deserialize; use crate::model::diesel::dict::dict_schema::*; #[derive(Queryable,Debug,Serialize,Deserialize,Default)] pub struct Test { pub id: i64, pub tags: i64, }
- 最小复现main入口代码:
#[macro_use] extern crate diesel; mod model; use diesel::{ ExpressionMethods, QueryDsl}; fn main() { get_bill_book_account_sum(); } pub fn get_bill_book_account_sum(){ use crate::diesel::GroupByDsl; use diesel::dsl::max; use crate::model::diesel::dict::dict_schema::test as bill_record_table; let source_query = bill_record_table::table .group_by(bill_record_table::id) .select((max(bill_record_table::tags),bill_record_table::id)) .filter(bill_record_table::dsl::tags.eq(9)); }
错误原因
两个问题导致编译失败:
- 函数定义存在笔误:开头多写了一个
f,把pub错写成fpub,属于基础语法错误。 - Diesel 1.4.x版本对聚合查询的链式调用顺序有严格类型校验要求:
select方法必须在group_by方法之前调用。如果先调用group_by再调用select,Diesel的类型系统会误将聚合函数(比如示例中的max)识别为普通非聚合列做校验,最终抛出NonAggregatetrait未实现的错误。
修复方法
修正笔误,同时调整查询构造器的调用顺序,把select放到group_by之前即可,修改后的可正常编译的代码如下:
pub fn get_bill_book_account_sum(){ use crate::diesel::GroupByDsl; use diesel::dsl::max; use crate::model::diesel::dict::dict_schema::test as bill_record_table; let source_query = bill_record_table::table .select((max(bill_record_table::tags),bill_record_table::id)) .group_by(bill_record_table::id) .filter(bill_record_table::dsl::tags.eq(9)); }
补充说明:Diesel 1.x版本写聚合查询时,固定遵循select -> group_by -> having -> filter/order/limit的链式调用顺序,就不会触发这类类型校验错误。
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

