如何在Rust中内部连接到自己使用的柴油?

disho6za  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(116)

我有一个例子,我需要从一个表block_headers内部连接到它本身,因为同一个表中存在父子关系。我已经尝试了许多不同的模式/模型/属性等组合。使用Diesel的ORM功能,但还没有找到一种方法来使其工作/编译。
对于这个问题,我已经把事情减少到最低限度了。
表的定义是:

table! {
    // Note: This is not the real PK of the table, but Diesel seems to require one.
    // I'm only querying this table so I simply chose a column.
    block_headers (block_height) { 
        block_height -> Integer,  // INTEGER NOT NULL
        index_block_hash -> Text, // TEXT NOT NULL
        parent_block_id -> Text   // TEXT NOT NULL
    }
}

在这种情况下,子节点的parent_block_id指向父节点的index_block_hash。内部连接到自身的原因是因为在给定的block_height上可能有多个块,但只有一个是有效的(有一个子块指向自身的那个)。下面是查询结果的一个简短示例:

0|55c9861be5cff984a20ce6d99d4aa65941412889bdc665094136429b84f8c2ee|ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1|918697ef63f9d8bdf844c3312b299e72a231cde542f3173f7755bb8c1cdaf3a7|55c9861be5cff984a20ce6d99d4aa65941412889bdc665094136429b84f8c2ee
2|ca4b40509fa64c3676038b2c0f868559d1583c76617dee7b958028b17cc141b1|918697ef63f9d8bdf844c3312b299e72a231cde542f3173f7755bb8c1cdaf3a7
3|48edeb155557b9f301eea81343df18110ce642d093c4d689223492a57b9f3f0d|ca4b40509fa64c3676038b2c0f868559d1583c76617dee7b958028b17cc141b1
4|d2ffe2e8d03755ebe8a8285ac075de76cac4888ee9f8fce4b03c5a651b0eac54|48edeb155557b9f301eea81343df18110ce642d093c4d689223492a57b9f3f0d
5|537b9aaa545ed03635a58d092c5b9d585d78f8cb1e1214a8a7cfd20aa96d4718|d2ffe2e8d03755ebe8a8285ac075de76cac4888ee9f8fce4b03c5a651b0eac54
6|02006dc91b18f1d6eadf909e81e8fce5894591fd56030adc5868f62a6d005083|537b9aaa545ed03635a58d092c5b9d585d78f8cb1e1214a8a7cfd20aa96d4718

我在这个例子中尝试实现的SQL是:

SELECT 
    bh1.block_height, 
    bh1.index_block_hash 
  FROM 
    block_headers bh1 
  INNER JOIN 
    block_headers bh2 ON bh2.parent_block_id = bh1.index_block_hash 
  ORDER BY bh1.block_height ASC

我最新尝试的模型看起来像:

#[derive(Queryable, Selectable, Identifiable, PartialEq, Eq, Debug, Clone, Associations)]
#[diesel(primary_key(block_height))]
#[diesel(belongs_to(BlockHeader, foreign_key = parent_block_id))]
#[diesel(table_name = block_headers)]
pub struct BlockHeader {
    pub block_height: i32,
    pub index_block_hash: String,
    pub parent_block_id: String
}

注意:我已经尝试了一些变化与belongs_toforeign_key等。但我试过的都编译不了
最后,我 * 尝试 * 做的是类似以下的事情,使用Diesel:

let result = block_headers::table
    .inner_join(block_headers::table.on(block_headers::parent_block_id.eq(block_headers::index_block_hash)))
    .filter(block_headers::index_block_hash.eq(&self.block_hash))
    .first::<BlockHeader>()
    .optional();

这将导致以下文本墙:

type mismatch resolving `<Once as Plus<Once>>::Output == Once`
2 redundant requirements hidden
required for `((block_height, index_block_hash, parent_block_id), (block_height, index_block_hash, parent_block_id))` to implement `diesel::AppearsOnTable<diesel::query_source::joins::Join<schema::block_headers::table, schema::block_headers::table, diesel::query_source::joins::Inner>>`
the full type name has been written to '/home/cylwit/Code/github.com/stacks-network/clarity-wasm/target/debug/deps/clarity_ab_tester-313c89c783028c52.long-type-10333939363849624741.txt'
required for `diesel::query_source::joins::Join<schema::block_headers::table, schema::block_headers::table, diesel::query_source::joins::Inner>` to implement `diesel::QuerySource`
1 redundant requirement hidden
required for `JoinOn<Join<table, table, Inner>, Grouped<Eq<parent_block_id, index_block_hash>>>` to implement `diesel::QuerySource`
the full type name has been written to '/home/cylwit/Code/github.com/stacks-network/clarity-wasm/target/debug/deps/clarity_ab_tester-313c89c783028c52.long-type-9677256780905495163.txt'
required for `diesel::query_builder::select_statement::SelectStatement<diesel::query_builder::from_clause::FromClause<schema::block_headers::table>>` to implement `diesel::query_dsl::InternalJoinDsl<schema::block_headers::table, diesel::query_source::joins::Inner, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<schema::block_headers::columns::parent_block_id, schema::block_headers::columns::index_block_hash>>>`
1 redundant requirement hidden
required for `schema::block_headers::table` to implement `diesel::query_dsl::InternalJoinDsl<schema::block_headers::table, diesel::query_source::joins::Inner, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<schema::block_headers::columns::parent_block_id, schema::block_headers::columns::index_block_hash>>>`
required for `schema::block_headers::table` to implement `diesel::query_dsl::JoinWithImplicitOnClause<diesel::query_source::joins::OnClauseWrapper<schema::block_headers::table, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<schema::block_headers::columns::parent_block_id, schema::block_headers::columns::index_block_hash>>>, diesel::query_source::joins::Inner>`rustcClick for full compiler diagnostic
context.rs(233, 14): required by a bound introduced by this call
schema.rs(5, 9): required for `schema::block_headers::columns::block_height` to implement `diesel::AppearsOnTable<diesel::query_source::joins::Join<schema::block_headers::table, schema::block_headers::table, diesel::query_source::joins::Inner>>`
mod.rs(521, 15): required by a bound in `diesel::QueryDsl::inner_join`
type mismatch resolving `<Once as Plus<Once>>::Output == Once`
2 redundant requirements hidden
required for `((block_height, index_block_hash, parent_block_id), (block_height, index_block_hash, parent_block_id))` to implement `diesel::AppearsOnTable<diesel::query_source::joins::Join<schema::block_headers::table, schema::block_headers::table, diesel::query_source::joins::Inner>>`
the full type name has been written to '/home/cylwit/Code/github.com/stacks-network/clarity-wasm/target/debug/deps/clarity_ab_tester-b6173cfc79c11f16.long-type-15833938815560068956.txt'
required for `diesel::query_source::joins::Join<schema::block_headers::table, schema::block_headers::table, diesel::query_source::joins::Inner>` to implement `diesel::QuerySource`
1 redundant requirement hidden
required for `JoinOn<Join<table, table, Inner>, Grouped<Eq<parent_block_id, index_block_hash>>>` to implement `diesel::QuerySource`
the full type name has been written to '/home/cylwit/Code/github.com/stacks-network/clarity-wasm/target/debug/deps/clarity_ab_tester-b6173cfc79c11f16.long-type-11396126599150083555.txt'
required for `diesel::query_builder::select_statement::SelectStatement<diesel::query_builder::from_clause::FromClause<schema::block_headers::table>>` to implement `diesel::query_dsl::InternalJoinDsl<schema::block_headers::table, diesel::query_source::joins::Inner, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<schema::block_headers::columns::parent_block_id, schema::block_headers::columns::index_block_hash>>>`
1 redundant requirement hidden
required for `schema::block_headers::table` to implement `diesel::query_dsl::InternalJoinDsl<schema::block_headers::table, diesel::query_source::joins::Inner, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<schema::block_headers::columns::parent_block_id, schema::block_headers::columns::index_block_hash>>>`
required for `schema::block_headers::table` to implement `diesel::query_dsl::JoinWithImplicitOnClause<diesel::query_source::joins::OnClauseWrapper<schema::block_headers::table, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<schema::block_headers::columns::parent_block_id, schema::block_headers::columns::index_block_hash>>>, diesel::query_source::joins::Inner>`rustcClick for full compiler diagnostic
context.rs(233, 14): required by a bound introduced by this call
schema.rs(5, 9): required for `schema::block_headers::columns::block_height` to implement `diesel::AppearsOnTable<diesel::query_source::joins::Join<schema::block_headers::table, schema::block_headers::table, diesel::query_source::joins::Inner>>`
mod.rs(521, 15): required by a bound in `diesel::QueryDsl::inner_join`

我真的不确定我尝试过的Diesel查询引擎如何处理bh1与在这个问题的顶部的SQL中的bh2别名.我也试过使用bh 1和bh 2的不同变量来分开,但结果几乎一样。
也许不可能使用Diesel的ORM功能,我需要使用原始SQL?

ss2ws0br

ss2ws0br1#

这个错误消息实质上是说你的一个表在from子句中出现了不止一次。这是一个很明显的错误,因为它不再清楚某个列引用哪个表。在这种情况下,您需要为至少一个表使用别名。这可以通过diesel提供的alias!宏来完成。
您的查询将类似于:

let (bh1, bh2) = diesel::alias!(block_headers as bh1, block_headers as bh2);

let result = bh1.inner_join(bh2.on(bh1.field(block_headers::parent_block_id).eq(bh2.field(block_headers::index_block_hash))))
    .filter(bh1.field(block_headers::index_block_hash).eq(&self.block_hash))
    .select(bh1.fields((block_headers::block_height, block_headers::index_block_hash, block_headers::parent_block_id)))
    .first::<BlockHeader>()
    .optional();

我还添加了一个显式的select,以便查询返回的内容与BlockHeader类型的结构相匹配。

相关问题