SQLAlchemy,选择这样的A至少有一个B带有凸起的标志

时间:2014-09-23 02:49:46

标签: python sql postgresql sqlalchemy one-to-many

我有两张桌子:

class A(Base):
    id = Column(Integer, primary_key=True)

class B(Base):
    id = Column(Integer, primary_key=True)

    a_id = Column(Integer, ForeignKey('a.id'))
    a = relationship(A)
    flag = Column(Boolean, default=False)

如您所见 - 来自B的每个对象与来自A的一个对象相关,而且,来自B的一个对象可以与来自A的单个对象相关。
我需要选择所有A至少有一个相关B且标志为== False的A。
现在我正在考虑这样的事情:

    selection = session.query(A).\
        join(B).\
        filter(
            B.a_id == A.id,
            B.flag == False,
        ).\
        group_by(A)

但我不确定两件事:

  1. 如果此查询正确无误? (我正在处理大量数据,测试这个数据非常复杂。)

  2. 如果从sqlalchemy哲学的角度来看这个查询是正确的吗? (我是新手)。

2 个答案:

答案 0 :(得分:1)

拟合查询将使用EXISTS半连接:

SELECT * FROM A
WHERE  EXISTS (SELECT 1 FROM B WHERE a_id = A.id AND flag = FALSE);

为了加快速度,你应该在B上只有a_id任何索引,只有flag = FALSE或第一个表达式。如果条件CREATE INDEX b_some_nmae_idx ON b(a_id) WHERE flag = FALSE; 的查询很常见,请考虑部分索引,如:

B

加入所有匹配的EXISTS行并再次聚合(就像你在问题中一样)是很多毫无意义的工作。只要找到B中的第一个匹配行,{{1}}就会停止。

答案 1 :(得分:1)

在关系中添加backref

class B(Base):
    # ...
    a = relationship(A, backref="b_s")

然后@ Erwin sqlalchemy版本的SQL verino如下:

qry = session.query(A).filter(A.b_s.any(B.flag == False))

如果您不想或不能将backref添加到关系中,以下内容将针对简单案例生成相同的查询,但是如果您有更多内容,则应密切关注生成的SQL复杂的查询,因为连接可能需要更多调整:

qry = (session.query(A).filter(
    exists(select([1]).where(B.a_id == A.id).where(B.flag == False)))
)