SeaQL / SeaQL/sea-orm

Column reference is ambiguous error occurs when two tables have the same field

Open
#3,142 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
9.9k
Forks
734
Avg merge
6h 36m
Merged PRs (30d)
8

Description

Description

I encountered a Query Error: column reference "code" is ambiguous when using the pagination feature on a query that involves multiple LEFT JOINs and a LIKE filter on a column that exists in more than one of the joined tables.
It appears that the SQL generated by sea-orm does not correctly qualify the column names in the WHERE clause, resulting in an ambiguity error.

Steps to Reproduce

pub async fn find_pagination<Entity, Column, Model, C, F>(
    select: Select<Entity>,
    default_order_columns: Vec<OrderColumn<Column>>,
    page_index: u64,
    page_size: u64,
    sort: Vec<SortField>,
    db: &C,
    handle: F,
) -> anyhow::Result<PaginationResult<Model>>
where
    Entity: EntityTrait<Model = Model>,
    Model: FromQueryResult + Sized + Send + Sync + JsonSchema,
    Column: ColumnTrait,
    C: ConnectionTrait,
    F: AsyncFnOnce(Select<Entity>) -> anyhow::Result<Select<Entity>>,
{
    let select = if sort.is_empty() {
        add_default_order(select, default_order_columns)
    } else {
        select
    };
    let select = add_sorter::<Entity, Column>(select, sort)?;
    let select = handle(select).await?;
    let paginator = select.paginate(db, page_size);
    let items_pages_num = paginator.num_items_and_pages().await?;
    let (items, info) = paginator
        .fetch_page(page_index)
        .await
        .map(|p| (p, items_pages_num))?;
    Ok(PaginationResult::from(page_index, page_size, items, info))
}

pub async fn find_pagination(
    db: &DbConn,
    user_id: i64,
    params: PaginationParams<JobFilter>,
) -> anyhow::Result<PaginationResult<entity::job::Model>> {
    find_pagination(
        entity::job::Entity::find()
            .join(
                JoinType::LeftJoin,
                crate::entity::job::Relation::SqlJob.def(),
            )
            .join(
                JoinType::LeftJoin,
                crate::entity::job::Relation::DataSyncJob.def(),
            )
            .join(
                JoinType::LeftJoin,
                crate::entity::job::Relation::ShellJob.def(),
            ),
        vec![OrderColumn {
            column: entity::job::Column::CreatedAt,
            order_desc: true,
        }],
        params.page_index,
        params.page_size,
        params.sort_query.sort,
        db,
        async |mut selector| {
            selector = selector.filter(Expr::col(entity::job::Column::Current).eq(true));
            if let Some(id) = params.filter.id {
                let id: i64 = id.parse()?;
                selector = selector.filter(Expr::col(entity::job::Column::JobId).eq(id));
            }
            selector = selector.filter(
                Self::extra_params_condition(db, user_id, params.filter.perm_type).await?,
            );
            if let Some(kind) = params.filter.kind {
                selector =
                    selector.filter(Expr::col(entity::job::Column::Kind).eq(kind.as_ref()));
            }
            if let Some(name) = params.filter.name {
                selector = selector
                    .filter(Expr::col(entity::job::Column::Name).like(format!("%{}%", name)));
            }
            if let Some(code) = params.filter.code {
                selector = selector.filter(
                    Condition::any()
                        .add(
                            Expr::col(entity::sql_job::Column::Code)
                                .like(format!("%{}%", code)),
                        )
                        .add(
                            Expr::col(entity::data_sync_job::Column::SelectSql)
                                .like(format!("%{}%", code)),
                        )
                        .add(
                            Expr::col(entity::data_sync_job::Column::PreInsertSql)
                                .like(format!("%{}%", code)),
                        )
                        .add(
                            Expr::col(entity::shell_job::Column::Code)
                                .like(format!("%{}%", code)),
                        ),
                );
            }
            Ok(selector)
        },
    )
    .await
}

Both the "sql_job" and "shell_job" tables have a "code" field. The program will report an error when the query conditions include a code filter condition:
Query Error: error returned from database: column reference "code" is ambiguous at line 846

Expected Behavior

Return job paginations

Actual Behavior

Query Error: error returned from database: column reference "code" is ambiguous at line 846

Reproduces How Often

100%

Workarounds

None known.

Versions

rustc 1.97.0 (2d8144b78 2026-07-07)
sea-orm v2.0.0
PostgreSQL 18.4-alpine
The image packaged based on alpine3.24.1 runs on Debian13

│ │ ├── sea-orm v2.0.0
│ │ │ ├── sea-orm-macros v2.0.0 (proc-macro)
│ │ │ │ ├── sea-bae v0.2.1 (proc-macro)
│ │ │ ├── sea-query v1.0.1
│ │ │ │ ├── sea-query-derive v1.0.0 (proc-macro)
│ ├── sea-orm v2.0.0
│ │ ├── sea-orm-macros v2.0.0 (proc-macro) ()
│ │ ├── sea-query v1.0.1
│ │ │ ├── sea-query-derive v1.0.0 (proc-macro) (
)
│ │ ├── sea-query-sqlx v0.9.1
│ │ │ ├── sea-query v1.0.1 ()
├── sea-orm v2.0.0 (
)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the failing pagination query from the find_pagination example with the joined sql_job and shell_job tables and the code filter. Trace the generated SQL and the pagination query path to find where column qualification is lost. Done means the same filtered pagination succeeds without an ambiguous-column error, with coverage for the reproduced case.

Written by the indexing model from the issue text.

Assessment

Tech stack
postgresql, rust, sql
Domain
backend, databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.