混合属性表达式:一对多的多边聚合属性

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

假设这些模型:

class A(Base):
    ...
    targets = relationship("B", back_populates='a')
    ...

class B(Base):
    ...
    a_id = Column(Integer, ForeignKey('a.id'))
    a = relationship("A", back_populates='targets')
    attr = Column(ENUM('a', 'b', 'c', name='options'), default='a')
    ...

我怎么能写一个hybrid_attribute.expression为所有As返回True,其中任何相关的Bs在attr中有('b', 'c')属性值? (如果没有相关的Bs,这也应该返回False。)

这让我走到了一半:

# hybrid_attribute expression in A model
@example_attr.expression
def example_attr(cls):
    return case(
        [
            (
                B.attr.in_(('b','c')),
                True
            )
        ],
        else_=False
    )

但是接下来我如何通过q​​azxswpoi对它们进行分组,如果有任何相关的A.ids是B那么True列的example_attr列值是A

我希望能够做到:True

编辑1:

这个SQL似乎提供了所需的结果:

session.query(A).filter(A.example_attr.is_(True)).all()

但是我在引用子查询中的别名字段时遇到了一个小问题:

select a.id, coalesce(bool_or(a_id_b_attr.status), false)
    from a left outer join (
        select b.a_id as a_id, b.attr in ('b', 'c') as status from b
    ) as a_id_b_attr
    on a.id = a_id_b_attr.a_id group by a.id;

这引发了sub = db.session.query(B.a_id.label('a_id'), B.attr.in_(('b', 'c')).label('status')).subquery() db.session.query( A.id, db.func.coalesce( db.func.bool_or(sub.status), False ) ).\ outerjoin(sub, A.id == sub.key_id).\ group_by(A.id) 看到AttribubteError没有任何别名归因。

python sql postgresql sqlalchemy
1个回答
3
投票

我怎么能写一个sub来为所有人返回hybrid_attribute.expression哪里有任何相关的B在True中有一个attr属性值? (如果没有相关的B,这也应该返回('b', 'c')。)

您可以使用EXISTS子查询表达式:

False

这不依赖于任何分组,而是依赖,并且可以直接在您想要的查询中使用:

class A(Base):
    __tablename__ = 'a'
    id = Column(Integer, primary_key=True)
    targets = relationship("B", back_populates='a')

    @hybrid_property
    def example_attr(self):
        return any(b.attr in {'b', 'c'} for b in self.targets)

    @example_attr.expression
    def example_attr(cls):
        return exists().\
            where(and_(B.a_id == cls.id,
                       B.attr.in_(['b', 'c']))).\
            correlate(cls)

class B(Base):
    __tablename__ = 'b'
    id = Column(Integer, primary_key=True)
    a_id = Column(Integer, ForeignKey('a.id'))
    a = relationship("A", back_populates='targets')
    attr = Column(ENUM('a', 'b', 'c', name='options'), default='a')

Postgresql能够使用相关的EXISTS子查询表达式重写(某些)查询到# Note that comparing booleans with booleans is a bit redundant session.query(A).filter(A.example_attr).all() ,因此关于相关性的通常性能注释可能不适用。

如果你想使用分组来处理这个问题,你可以使用semijoins和显式连接:

bool_or

Postgresql允许在此分组查询中选择session.query(A).\ join(B).\ group_by(A.id).\ having(func.bool_or(B.attr.in_(['b', 'c']))).\ all() 的所有列,即使它们不是聚合表达式,因为它们在功能上依赖于分组列 - 换句话说,A确定所选列。

© www.soinside.com 2019 - 2024. All rights reserved.