在柴油机中执行正确连接

Posted

技术标签:

【中文标题】在柴油机中执行正确连接【英文标题】:Performing a Right Join in Diesel 【发布时间】:2020-05-09 19:08:31 【问题描述】:

我有一个函数,它接受两个可选的过滤参数,如果提供了这些参数,则过滤表中的数据。为此,我创建了一个盒装查询。我想用这个盒装查询创建一个右连接。 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 函数吗?

【问题讨论】:

【参考方案1】:

在任何情况下,右连接都等同于具有反转表顺序的左连接。 (例如,参见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&lt;(UserGroup, Option&lt;Group&gt;)&gt;。如果你想要一些不同的东西,你需要编写一个自定义选择子句来指定所需的结果形状。

【讨论】:

以上是关于在柴油机中执行正确连接的主要内容,如果未能解决你的问题,请参考以下文章

如何选择带有柴油 rs 的列子集?

如何使用柴油进行 IN 查询?

如何在 Apache PIG 中正确执行此内部连接?

柴油查询中的“听起来像”

SqlDelight/SQLite 没有正确执行连接?

如何为具有映射到多个柴油列的自定义字段的类型派生 Queryable?