SeaORM查询中MySQL RANK() OVER始终返回0的问题求助
问题:SeaORM中MySQL窗口函数
RANK()返回值始终为0的解决办法 问题描述
在Rust项目中使用SeaORM框架,通过MySQL的RANK() OVER (ORDER BY ...)函数获取用户余额排名时,查询结果里的rank字段始终返回0,直接在MySQL中执行相同查询却能得到正确结果。
Rust代码示例
#[allow(unused_imports)] use loco_rs::{cli::playground, prelude::*}; use myapp::app::App; use myapp::models::_entities::wallets::{self, ActiveModel, Entity, Model}; use sea_orm::{DatabaseConnection, DbBackend, Statement, Value}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Debug)] struct UserRank { name: String, rank: i64, balance: i32, } #[tokio::main] async fn main() -> loco_rs::Result<()> { let _ctx = playground::<App>().await?; let db = &_ctx.db; let coins_query = r#" SELECT t.first_name, t.last_name, w.coins, RANK() OVER (ORDER BY w.coins DESC) AS `rank` FROM wallets w JOIN game_users g ON w.game_user_id = g.id JOIN telegram_users t ON g.id = t.game_user_id ORDER BY w.coins DESC LIMIT 10; "#; let coins = db .query_all(Statement::from_string(DbBackend::MySql, coins_query)) .await .unwrap() .into_iter() .map(|row| UserRank { name: format!( "{} {}", row.try_get::<String>("", "first_name").unwrap_or_default(), row.try_get::<String>("", "last_name").unwrap_or_default() ), rank: row.try_get::<i64>("", "rank").unwrap_or(0), // 始终返回0 balance: row.try_get::<i32>("", "coins").unwrap_or(0), }) .collect::<Vec<_>>(); println!("User Ranks: {:#?}", coins); Ok(()) }
意外输出
User Ranks: [ UserRank { name: "Alok Alok", rank: 0, // 预期为1 balance: 1290, }, UserRank { name: "Alok2 Alok2 ", rank: 0, // 预期为2 balance: 0, }, ]
已尝试的解决方法
- 将
UserRank结构体中的rank字段类型从i32改为i64; - 将别名用反引号包裹:
rank: row.try_get::<i64>("", "rank").unwrap_or(0),; - 直接在MySQL中运行该查询(可正常返回正确排名)。
问题原因及解决办法
原因分析
问题出在try_get方法的使用上:
try_get的第一个参数是表名,而rank是窗口函数生成的计算列,没有对应的表名,传空字符串会导致列名匹配失败;- 匹配失败后触发
unwrap_or(0),返回默认值0。
解决方法
方案1:使用try_get_by_name方法
该方法无需指定表名,直接通过列名获取值,更适合处理计算列:
.map(|row| UserRank { name: format!( "{} {}", row.try_get_by_name::<String>("first_name").unwrap_or_default(), row.try_get_by_name::<String>("last_name").unwrap_or_default() ), rank: row.try_get_by_name::<i64>("rank").unwrap_or(0), balance: row.try_get_by_name::<i32>("coins").unwrap_or(0), })
方案2:修改try_get的表名参数
如果坚持使用try_get,将第一个参数设为None(表示无对应表名):
rank: row.try_get::<i64>(None, "rank").unwrap_or(0),
验证
修改后重新运行代码,rank字段会正确返回MySQL窗口函数计算出的排名值,与直接在数据库中查询的结果一致。
内容的提问来源于stack exchange,提问作者Alok
相关产品推荐
相关产品推荐

