如何使用 Diesel 执行“更新自”?

Posted

技术标签:

【中文标题】如何使用 Diesel 执行“更新自”?【英文标题】:How do I perform an `UPDATE FROM` using Diesel? 【发布时间】:2020-10-27 21:18:59 【问题描述】:

假设我有三个表,abc

create table c (
  id serial primary key,
  can_edit_b boolean not null
);
create table b (
  id serial primary key,
  value text not null
);
create table a (
  id serial primary key,
  c_id integer not null references c(id),
  b_id integer not null references b(id)
);

我想更新b(给定c 实例的ID)只要c 的实例被a 的实例引用,该实例也引用bc.can_edit_b是真的。我想做的SQL:

update b
set value = "some value"
from c, a
where a.b_id == b.id
where a.c_id == <user id (inserted as a Rust i32)>
where c.can_edit_b == true

我找不到对应于 SQL from 的 relevant method/function in Diesel's API。如果我尝试使用inner_join,那么编译器会告诉我inner_join 没有为UpdateStatement 定义。

【问题讨论】:

很难回答您的问题,因为它不包含minimal reproducible example。我们无法分辨代码中存在哪些 crate(及其版本)、类型、特征、字段等。如果您尝试在全新的 Cargo 项目中重现您的设置和错误,我们会更轻松地为您提供帮助,然后 edit 您的问题将包含其他信息。您可以使用Rust-specific 和Diesel-specific MRE 提示来减少您在此处发布的原始代码。谢谢! 【参考方案1】:

您可以加入表格,应用过滤器,然后将其用作更新条件:

#[macro_use]
extern crate diesel; // 1.4.5, features = ["postgres"]

use diesel::prelude::*;

table! 
    a 
        id -> Integer,
        c_id -> Integer,
        b_id -> Integer,
    


table! 
    b 
        id -> Integer,
        value -> VarChar,
    


table! 
    c 
        id -> Integer,
        can_edit_b -> Bool,
    


joinable!(a -> b (b_id));
joinable!(a -> c (c_id));

allow_tables_to_appear_in_same_query!(a, b, c);

fn example(arg: i32) 
    let all_joined = a::table.inner_join(b::table).inner_join(c::table);
    let matching_rows = all_joined
        .filter(a::c_id.eq(arg))
        .filter(c::can_edit_b.eq(true));

    let update_stmt = diesel::update(b::table)
        .filter(b::id.eq_any(matching_rows.select(b::id)))
        .set(b::value.eq("some value"));

    println!("", diesel::debug_query::<diesel::pg::Pg, _>(&update_stmt));


fn main() 
    example(42);

这会生成与您的不同的 SQL,但应该会产生相同的结果:

UPDATE "b"
SET "value" = $1
WHERE "b"."id" IN
    (SELECT "b"."id"
     FROM (("a"
            INNER JOIN "b" ON "a"."b_id" = "b"."id")
           INNER JOIN "c" ON "a"."c_id" = "c"."id")
     WHERE "a"."c_id" = $2
       AND "c"."can_edit_b" = $3) -- binds: ["some value", 42, true]

另见:

How do I perform a delete with sub-query in Diesel against a Postgres database?

【讨论】:

以上是关于如何使用 Diesel 执行“更新自”?的主要内容,如果未能解决你的问题,请参考以下文章

如何在生产中使用 Rocket 运行 Diesel 迁移?

如何使用 SQL 函数和用户提供的输入创建自定义 Diesel 查询?

如何在 Diesel 中对 Postgres 数据库执行删除子查询?

如何使用 Diesel 将 i64 与 Insertable 一起使用

如何使用 Diesel 计算数组列中不同元素的数量?

如何使用 Diesel 和 SQLite 获取新创建值的 id?