使用SQLAlchemy生成带有子查询作为select语句中的列的sql

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

有没有办法让 SQLAlchemy 生成一个带有自定义列的查询,该列是与当前行相关的子查询:

SELECT
 tab1.id,
 tab1.col1, 
 ...,
 (
     SELECT count(1) FROM tab2 
     WHERE tab2.tab1_id = tab1.id
     GROUP BY tab2.col1
 ) as cnt
FROM tab1
WHERE ...
LIMIT 100

使用 ORM API?

session.query(Tab1, ?(subquery for additional column)?).filter(...).limit(100)

我正在使用 PostgreSQL 9.3 和旧版本的 SQLAlchemy 0.9.8

python postgresql sqlalchemy correlated-subquery
3个回答
21
投票

如果您经常需要此功能,并且/或计数是您的

Tab1
模型的组成部分,则应使用混合属性,如其他答案中所述。另一方面,如果您仅需要单个查询,那么您可以使用
Query.label()
Query.as_scalar()
:

创建标量子查询
count_stmt = session.query(func.count(1)).\
    filter(Tab2.tab1_id == Tab1.id).\
    group_by(Tab2.col1).\
    label('cnt')

session.query(Tab1, count_stmt).filter(...).limit(100)

子查询将自动关联它可以从封闭查询中得到什么。


3
投票

你可以这样做,但它的工作方式与你编写的方式完全不同。您可以创建 Tab1 的一个属性,该属性取决于与 tab2 的关系(假设

tab2.tab1_id
是外键,它应该是。

你的模型看起来像这样:

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    children = relationship("Child")

class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parent.id'))

根据有关关系的文档

然后你可以添加类似的内容

@hybrid_property
def number_of_children(self):
    if self.children:
        return len(self.children)
    return 0

@number_of_children.expression
def number_of_children(cls):
    return (select([func.count(Child.id)])
            .where(Child.cover_id == cls.id))

对于父模型,按照这个答案更多文档

完成此操作后,您可以像任何其他基于列的属性一样过滤此属性。


0
投票

对于 SQLAlchemy 2 用户

只需为您的子查询语句定义一个

select
语句即可。然后,您可以将其用作另一个
select
语句中的列。

使用 Ilja Everilä 的例子:

count_stmt = (select(func.count(1))
              .where(Tab2.tab1_id == Tab1.id)
              .group_by(Tab2.col1)
              .scalar_subquery()
              .label('cnt')

更多详细信息请参阅 SQLAlchemy 2.0 文档

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