Diesel: Добавление результата подзапросов

Учитывая следующие таблицы:

accounts (
  id INTEGER,
  opening_balance INTEGER,
)

transactions (
  debit INTEGER,
  credit INTEGER,
  amount INTEGER

  foreign key debit references accounts (id),
  foreign key credit references accounts (id)
)

Я хочу выполнить следующий SQL-запрос:

select
  id,
  opening_balance
  + (select sum(amount) from transactions where debit = account_id)
  - (select sum(amount) from transactions where credit = account_id)
from accounts;

Я пробовал что-то вроде этого:

accounts
    .select((
        id,
        opening_balance
            + transactions::table
                .select(sum(transactions::amount))
                .filter(transactions::debit.eq(id))
            - transactions::table
                .select(sum(transactions::amount))
                .filter(transactions::credit.eq(id)),
    ))

Хотя отдельные части этого запроса работают нормально, я не могу его скомпилировать.

the trait bound 
`diesel::query_builder::SelectStatement<schema::transactions::table, diesel::query_builder::select_clause::SelectClause<aggregate_folding::sum::sum<diesel::sql_types::Integer, schema::transactions::columns::amount>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<schema::transactions::columns::debit, schema::fiscal_year_accounts::columns::account_id>>>: diesel::Expression`
is not satisfied
required because of the requirements on the impl of `AsExpression<diesel::sql_types::Integer>` for 
`diesel::query_builder::SelectStatement<schema::transactions::table, diesel::query_builder::select_clause::SelectClause<aggregate_folding::sum::sum<diesel::sql_types::Integer, schema::transactions::columns::amount>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<schema::transactions::columns::debit, schema::fiscal_year_accounts::columns::account_id>>>`

Операторы + и - работают со статическими значениями, но как заставить их работать с подзапросами?


person mhutter    schedule 31.05.2021    source источник


Ответы (1)


Прежде всего: всегда предоставляйте полный минимальный пример вашей проблемы. Это включает в себя точную версию всех используемых ящиков, все соответствующие импорты, чтобы ваш код действительно выдавал это сообщение об ошибке, полное сообщение об ошибке со всеми инструкциями справки и уведомлениями, а в случае с дизельными двигателями - сгенерированный файл схемы.

Чтобы ответить на ваш вопрос: вы пропустили два вызова .single_value(), который необходим для преобразования запроса в подзапрос, который можно использовать как выражение. Оба подзапроса возвращают Nullable<BigInt>, поэтому требуется, чтобы opening_balance соответствовал типу.

Для полноты картины см. рабочий код ниже.

#[macro_use]
extern crate diesel;
use diesel::prelude::*;

table! {
    accounts {
        id -> Integer,
        // changed to `BigInt` as a sum of `Integer` returns a `BigInt`
        opening_balance -> BigInt,
    }
}

table! {
    transactions {
        id -> Integer,
        amount -> Integer,
        debit -> Integer,
        credit -> Integer,
    }
}

allow_tables_to_appear_in_same_query!(accounts, transactions);

fn test() {
    use self::accounts::dsl::*;
    use diesel::dsl::sum;

    let _q = accounts.select((
        id,
        opening_balance.nullable() // call `.nullable()` here to explicitly mark it as potential nullable
            + transactions::table
                .select(sum(transactions::amount))
                .filter(transactions::debit.eq(id))
                .single_value() // call `.single_value()` here to transform this query into a subquery
            - transactions::table
                .select(sum(transactions::amount))
                .filter(transactions::credit.eq(id))
                .single_value(), // call `.single_value()` here to transform this query into a subquery
    ));
}
person weiznich    schedule 01.06.2021
comment
Привет, weiznich, правда, хотя я думаю, что включил всю необходимую информацию, MCVE отсутствовал ... Спасибо, что в любом случае прошли через проблемы! Я не знал о single_value(), недостающем бите. - person mhutter; 02.06.2021