postgresql - 在 Diesel 中执行正确的联接

标签 postgresql rust rust-diesel

我有一个函数,它接受两个可选的过滤参数,如果提供了这些参数,则过滤表中的数据。为此,我创建了一个盒装查询。我想用这个盒装查询创建一个正确的连接。 Diesel 的当前文档没有提到右连接,但它似乎更喜欢 belonging_to方法。我已将我的代码简化为一个示例:

#[macro_use] extern crate diesel;

use diesel::prelude::*;

table! {
    groups (id) {
        id -> Int4,
        name -> Text,
    }
}

table! {
    user_groups (id) {
        id -> Int4,
        user_id -> Int4,
        group_id -> Int4,
    }
}

allow_tables_to_appear_in_same_query!(groups, user_groups);

#[derive(Debug, Queryable)]
struct Group {
    id: i32,
    name: String,
}

#[derive(Debug, Queryable, Associations)]
#[belongs_to(Group)]
struct UserGroup {
    id: i32,
    user_id: i32,
    group_id: i32,
}

fn filter(
    name: Option<&str>,
    user_id: Option<i32>,
    conn: &diesel::PgConnection,
) -> Result<Vec<(Group, Vec<UserGroup>)>, Box<dyn std::error::Error>> {
    let mut query = groups::table
        .right_join(user_groups::table.on(groups::id.eq(user_groups::group_id))) // this method does not exist
        .into_boxed();
    if let Some(name) = name {
        query = query.filter(groups::name.eq(name));
    }
    if let Some(user_id) = user_id {
        query = query.filter(user_groups::user_id.contains(user_id)); // so this is just a guess
    }
    Ok(query.get_results(conn)?)
}

fn main() {
    let url = "postgres://question_usr:question_pwd:localhost:5432/question_db";
    let conn = diesel::PgConnection::establish(url).unwrap();
    let _ = filter(Some("groupname"), Some(4), &conn).unwrap();
}

意图是,如果参数 user_id被指定,只有 Groups 的行返回至少有一个 UserGroup使得 user_group.user_id == user_id .如何运行此查询?我是否需要使用 belonging_to以某种方式发挥作用?

最佳答案

右连接在任何情况下都等价于表顺序倒置的左连接。 (例如,参见 here)。因此 Diesel 仅提供构造 LEFT JOIN 的功能。 .

您的示例如下所示:

fn filter(
    name: Option<&str>,
    user_id: Option<i32>,
    conn: &diesel::PgConnection,
) -> Result<Vec<(UserGroup, Option<Group>)>, Box<dyn std::error::Error>> {
    let mut query = user_groups::table
        .left_join(groups::table.on(groups::id.eq(user_groups::group_id))) /
        .into_boxed();
    if let Some(name) = name {
        query = query.filter(groups::name.eq(name));
    }
    if let Some(user_id) = user_id {
        query = query.filter(user_groups::user_id.eq(user_id)); 
    }
    Ok(query.get_results(conn)?)
}

请注意,这将返回 Vec<(UserGroup, Option<Group>)>默认情况下。如果您想要不同的东西,您需要编写一个自定义选择子句,指定所需的结果形状。

关于postgresql - 在 Diesel 中执行正确的联接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59879785/

相关文章:

sqlite - 如何使用Diesel和SQLite获取新创建的值的ID?

rust - 为什么在将使用 Diesel 的特征重写为特征方法的函数时得到 "overflow evaluating the requirement"?

rust - 如何使用 Rocket 中的 Tera 模板在 HTML 中显示使用 Diesel 检索的值?

sql - 计算有序数组中节点之间的总距离

rust - 将自定义值添加到 Cargo.toml 文件中

PostgreSQL - 必须出现在 GROUP BY 子句中或用于聚合函数中

rust - 在结构中使用 vec

rust - 一个实现什么时候想要在 Rust 中获得 self 的所有权?

mysql - Rails .where 调用数据库显示开发中的图像 (mysql),但不显示生产中的图像 (postgres)

sql - SELECT 语句期间触及的表/列的列表