SQLAlchemy:一个查询中有几个计数

2024-05-26 07:47:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我很难优化我的SQLAlchemy查询。我的SQL知识非常基础,我只是无法从SQLAlchemy文档中获得我需要的东西。在

假设以下是非常基本的一对多关系:

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

class Child(Base):
    __tablename__ = "children"
    id = Column(Integer, primary_key = True)
    parent_id = Column(Integer, ForeignKey("parents.id"))
    naughty = Column(Boolean)

我怎么能:

  • 是否为每个父项查询(Parent, count_of_naughty_children, count_of_all_children)的元组?在

经过相当长时间的谷歌搜索,我发现了如何分别查询这些值:

^{pr2}$

我试着用不同的方法把它们结合起来,但没能得到我想要的。在

  • 查询所有有超过80%淘气孩子的家长?编辑:naughty可以为空。在

我想这个查询将基于上一个查询,按naughty/all比率过滤。在

感谢任何帮助。在

编辑:多亏了Antti Haapala的帮助,我找到了第二个问题的解决方案:

avg = func.avg(func.coalesce(Child.naughty, 0)) # coalesce() treats NULLs as 0
# avg = func.avg(Child.naughty) - if you want to ignore NULLs
session.query(Parent).join(Child, Parent.children).group_by(Parent).\
    having(avg > 0.8)

它查找子变量naughty的平均值,将False和NULLs视为0,将True视为1。用MySQL后端进行了测试,但也可以在其他系统上使用。在


Tags: idchildtruebasesqlalchemycolumnintegerclass
2条回答

count()sqlaggretate函数非常简单;它提供了每个组中非空值的总数。考虑到这一点,我们可以调整您的查询以获得正确的结果。在

print (Query([
    Parent,
    func.count(Child.id),
    func.count(case(
        [((Child.naughty == True), Child.id)], else_=literal_column("NULL"))).label("naughty")])

    .join(Parent.children).group_by(Parent)
    )

生成以下sql:

^{2}$

如果您的查询只是为了让拥有80%以上子女的父母顽皮,您可以在大多数数据库中将naughty转换为整数,然后取其平均值;然后having这个平均值大于0.8。在

所以你得到了

from sqlalchemy.sql.expression import cast

naughtyp = func.avg(cast(Child.naughty, Integer))
session.query(Parent, func.count(Child.id), naughtyp).join(Child)\
    .group_by(Parent.id).having(naughtyp > 0.8).all()

相关问题 更多 >