使用Axum+Sea-ORM查询PostgreSQL不同过滤条件的两列求和问题
解决Sea-ORM同时执行两个查询的类型标注问题
问题根源
当同时发起两个结构相似的聚合查询时,Rust编译器无法自动推断Select<Aggregate<Transaction, Sum<Amount>>>这类复杂泛型类型,必须显式标注变量类型才能消除歧义。
解决方案
在定义两个查询变量时,显式指定完整的查询类型,或者用类型别名简化重复代码。
修改后的核心代码示例
假设你的实体模块路径是crate::entities::transaction,金额字段为Amount,修改get("/")中的查询逻辑:
use sea_orm::{EntityTrait, QueryFilter, QueryAggregate, Sum}; use crate::entities::transaction; use chrono::{Utc, Duration}; async fn index(db: sea_orm::DatabaseConnection) -> String { let tomorrow = Utc::now().naive_utc() + Duration::days(1); // 显式标注支出总和的查询类型 let expense_sum_query: sea_orm::Select<sea_orm::Aggregate<transaction::Entity, Sum<transaction::Column::Amount>>> = transaction::Entity::find() .filter(transaction::Column::Expense.eq(true)) .filter(transaction::Column::Date.lt(tomorrow)) .aggregate(Sum(transaction::Column::Amount)); // 显式标注收入总和的查询类型 let income_sum_query: sea_orm::Select<sea_orm::Aggregate<transaction::Entity, Sum<transaction::Column::Amount>>> = transaction::Entity::find() .filter(transaction::Column::Expense.eq(false)) .filter(transaction::Column::Date.lt(tomorrow)) .aggregate(Sum(transaction::Column::Amount)); // 执行查询并处理空值(默认0.0) let expense_sum = expense_sum_query.one(&db).await.unwrap_or(Some(0.0)).unwrap_or(0.0); let income_sum = income_sum_query.one(&db).await.unwrap_or(Some(0.0)).unwrap_or(0.0); let balance = income_sum - expense_sum; format!("收入: {:.2}, 支出: {:.2}, 结余: {:.2}", income_sum, expense_sum, balance) }
简化方案:用类型别名减少重复
如果觉得类型声明太长,可提前定义类型别名:
use sea_orm::{EntityTrait, QueryFilter, QueryAggregate, Sum, Select, Aggregate}; use crate::entities::transaction; use chrono::{Utc, Duration}; // 定义类型别名复用 type AmountSumQuery = Select<Aggregate<transaction::Entity, Sum<transaction::Column::Amount>>>; async fn index(db: sea_orm::DatabaseConnection) -> String { let tomorrow = Utc::now().naive_utc() + Duration::days(1); let expense_sum_query: AmountSumQuery = transaction::Entity::find() .filter(transaction::Column::Expense.eq(true)) .filter(transaction::Column::Date.lt(tomorrow)) .aggregate(Sum(transaction::Column::Amount)); let income_sum_query: AmountSumQuery = transaction::Entity::find() .filter(transaction::Column::Expense.eq(false)) .filter(transaction::Column::Date.lt(tomorrow)) .aggregate(Sum(transaction::Column::Amount)); // 后续执行逻辑同上 let expense_sum = expense_sum_query.one(&db).await.unwrap_or(Some(0.0)).unwrap_or(0.0); let income_sum = income_sum_query.one(&db).await.unwrap_or(Some(0.0)).unwrap_or(0.0); let balance = income_sum - expense_sum; format!("收入: {:.2}, 支出: {:.2}, 结余: {:.2}", income_sum, expense_sum, balance) }
关键说明
- 单个查询时,编译器能通过后续
.one(&db)的调用上下文推断类型,但两个查询同时存在时,类型推导会产生歧义,必须显式标注。 - 也可以在获取查询结果时标注返回值类型(比如
let expense_sum: Option<f64> = ...),但显式标注查询变量类型的可读性更强。
内容的提问来源于stack exchange,提问作者eseacr17
相关产品推荐
相关产品推荐

