尝试将外部联接留给两个相关的表

时间:2013-10-03 18:34:20

标签: python sqlalchemy

我有三张桌子:

class Foo(Base):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)

class Bar(Base):
    __tablename__ = 'bar'
    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)

class Baz(Base):
    __tablename__ = 'baz'
    id = Column(Integer, primary_key=True)
    foo_id = Column(ForeignKey('foo.id'), nullable=True)
    foo = relationship('Foo', backref='bazes')
    bar_id = Column(ForeignKey('bar.id'), nullable=True)
    bar = relationship('Bar', backref='bazes')
    name = Column(String(100), nullable=False)

所以Baz将外键带回Foo和Bar。

Say Foo有三行,名称为a,b和c。并且说Bar有三行,名称为x,y和z。

我想执行一个查询来获取给定Foo和Bar的Baz中的行数,即使答案为0.对于返回值,这样的事情是这样的:

('a', 'x', 12)
('a', 'y', 3)
('a', 'z', 0)
('b', 'x', 9)
('b', 'y', 0)
('b', 'z', 1)
('c', 'x', 3)
('c', 'y', 6)
('c', 'z', 2)

对于单个相关表,我理解如何在Baz上执行子查询(按Baz.foo_id分组),然后查询Foo,使用Baz留下外连接。但是对于两个相关的表,我很茫然。是否可以在sqlalchemy中执行此查询?

1 个答案:

答案 0 :(得分:1)

我通常使用子查询来达到此目的。这是我将生成的SQL:

SELECT foo.name, bar.name, (SELECT COUNT('*') FROM baz WHERE baz.foo_id=foo.id AND baz.bar_id=bar.id) FROM foo, bar

在SQLAlchemy中:

count_query = session.query(func.count('*')).filter(Baz.foo_id==Foo.id).filter(Baz.bar_id==Bar.id).correlate(Bar).correlate(Foo).as_scalar()
query = session.query(Foo.name, Bar.name, count_query)

我对这个查询的性能与使用巧妙组合的OUTER JOIN的查询没有专家,所以我不确定这是否更慢。我原本会尝试类似的东西:

FROM foo LEFT OUTER JOIN baz ON foo.id=baz.foo_id RIGHT OUTER JOIN bar ON bar.id=baz.bar_id

我不确定这会产生你需要什么,现在我只有sqlite可用,它不支持RIGHT OUTER JOIN所以我无法测试这个。但我已经验证了上述查询生成了您想要的结果。