You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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方法的使用上:

  1. try_get的第一个参数是表名,而rank是窗口函数生成的计算列,没有对应的表名,传空字符串会导致列名匹配失败;
  2. 匹配失败后触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 20:05:07