在 ORM 查询中使用 joinedload 检索结果时获取 SELECT 语句有笛卡尔积警告

问题描述 投票:0回答:0

以下是我创建的数据库中的2个表。

class BusinessRole:
    __tablename__ = 'businessrole'

    id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    created_on = db.Column(db.DateTime, default=db.func.now())
    updated_on = db.Column(db.DateTime, default=db.func.now(), onupdate=db.func.now())
    name = db.Column(db.String(50), nullable=False)
    status = db.Column(db.String(50), nullable=False)
    approval_status = db.Column(db.String(50), nullable=False, default=BRApprovalStatus.VOID.value)
    approval = db.relationship('Approval', backref='approval')
    version = db.Column(db.Integer, nullable=False)


class Approval:
    __tablename__ = 'approval'
    
    id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    created_on = db.Column(db.DateTime, default=db.func.now())
    updated_on = db.Column(db.DateTime, default=db.func.now(), onupdate=db.func.now())
    requester = db.Column(db.String(120), nullable=False)
    approver = db.Column(db.String(120), nullable=False)

所以数据库有多个相同值的记录例如:

 1. Business_Role_1, updated_on: 2023-05-02, version: 2
 2. Business_Role_1, updated_on: 2023-05-01, version: 1
 3. Business_Role_2, updated_on: 2023-04-30, version: 3
 4. Business_Role_1, updated_on: 2023-04-29, version: 2
 5. Business_Role_1, updated_on: 2023-04-28, version: 1

所以我只检索那些最近更新并具有最高版本值的值。这是我为此编写的下面的查询。

sub_query = db.session.query(
        BusinessRole.name,
        func.max(BusinessRole.version).label('max_version'),
        func.max(BusinessRole.updated_on).label('latest_updated_on')
    ).filter(
        or_(and_(BusinessRole.status == BRStatus.APPROVED.value,
                 BusinessRole.approval_status == BRApprovalStatus.COMPLETED.value),
            and_(BusinessRole.status.in_([BRStatus.DRAFT.value, BRStatus.NEW.value, BRStatus.DENIED.value])))
    ).group_by(BusinessRole.name).subquery()

    # Comparing max version and role
    business_roles = db.session.query(BusinessRole).join(
        sub_query,
        and_(
            BusinessRole.version == sub_query.c.max_version,
            BusinessRole.updated_on == sub_query.c.latest_updated_on,
            BusinessRole.name == sub_query.c.name
        ))

所以根据上面的例子我得到了这些值

1. Business_Role_1, updated_on: 2023-05-02, version: 2
2. Business_Role_2, updated_on: 2023-04-30, version: 3

现在我想根据 Approval 表的 approver 字段对这些值进行排序,所以我将这一行添加到我编写的查询中。

from sqlalchemy.orm import joinedload
business_roles = business_roles.options(joinedload(BRModel.BusinessRole.approval))

当我运行这个查询时 我得到了结果,但这是错误的,我确实收到以下警告。

SELECT statement has a cartesian product between FROM element(s) "anon_2", "businessrole" and FROM element "approval".  Apply join condition(s) between each element to resolve.
items = self.limit(per_page).offset((page - 1) * per_page).all()

我该如何解决这个问题?

python mysql flask orm flask-sqlalchemy
© www.soinside.com 2019 - 2024. All rights reserved.