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

如何使用sqlx query_as查询模型部分字段并避免报错?

问题描述

我有一张名为order_data的表,包含timestamp类型的created_on字段和i32类型的order_id字段,想用不同方法查询这两个字段。

查询created_on的方法:

pub async fn fetch_last_created_on(pool: &Pool<Postgres>) -> Option<NaiveDateTime> {
    let result = match query_as::<Postgres, OrderDb>("select max(created_on) as created_on from order_data")
        .fetch_one(pool)
        .await
    {
        Ok(result) => result.created_on,
        Err(e) => {
            error!("Error fetching data: {}", e);
            None
        }
    };
    result
}

查询order_id的方法:

pub async fn fetch_all_order_ids(pool: &Pool<Postgres>) -> Option<HashSet<i32>> {
    let result = match query_as::<Postgres, OrderDb>("select order_id from order_data")
        .fetch_all(pool)
        .await
    {
        Ok(result) => Some(result.iter().map(|order| order.order_id.unwrap()).collect()),
        Err(e) => {
            error!("Error fetching data: {}", e);
            None
        }
    };

    result
}

定义的OrderDb结构体:

#[derive(FromRow)]
struct OrderDb {
    order_id: Option<i32>,
    created_on: Option<NaiveDateTime>,
}

调用fetch_last_created_on时出现错误:

no column found for name: order_id

我可以为每种查询定义单独的#[derive(FromRow)]结构体,但有没有更好的处理方式?注意我不使用宏,仅使用方法。


解决方案

方法一:使用query替代query_as,手动提取字段

放弃依赖FromRow结构体,直接处理查询返回的行数据,按需提取字段,无需为每个查询定义专属结构体。

修改fetch_last_created_on:

pub async fn fetch_last_created_on(pool: &Pool<Postgres>) -> Option<NaiveDateTime> {
    let result = match query("select max(created_on) as created_on from order_data")
        .fetch_one(pool)
        .await
    {
        Ok(row) => row.try_get("created_on").ok(),
        Err(e) => {
            error!("Error fetching data: {}", e);
            None
        }
    };
    result
}

修改fetch_all_order_ids:

pub async fn fetch_all_order_ids(pool: &Pool<Postgres>) -> Option<HashSet<i32>> {
    let result = match query("select order_id from order_data")
        .fetch_all(pool)
        .await
    {
        Ok(rows) => {
            let ids: Result<HashSet<i32>, _> = rows.into_iter()
                .map(|row| row.try_get("order_id"))
                .collect();
            ids.ok()
        }
        Err(e) => {
            error!("Error fetching data: {}", e);
            None
        }
    };

    result
}

这种方式完全避免了字段不匹配的问题,代码更简洁直接,适合简单查询场景。

方法二:为结构体字段添加#[from_row(default)]属性

如果希望保留OrderDb结构体的复用性,可以给字段添加#[from_row(default)]属性(需确保使用的FromRow实现支持该属性,例如sqlx的FromRow)。当查询结果缺少对应字段时,该字段会自动使用默认值(Option类型即为None),不会抛出错误。

修改后的结构体:

#[derive(FromRow)]
struct OrderDb {
    #[from_row(default)]
    order_id: Option<i32>,
    #[from_row(default)]
    created_on: Option<NaiveDateTime>,
}

这样无论查询返回单个字段还是多个字段,结构体都能正常解析,无需额外定义多个结构体。


内容的提问来源于stack exchange,提问作者Enigo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:35:19