如何使用 sqlalchemy 计算平均数?

Posted

技术标签:

【中文标题】如何使用 sqlalchemy 计算平均数?【英文标题】:How to take avg on count using sqlalchemy? 【发布时间】:2020-05-27 03:33:46 【问题描述】:

如何在 SQLAlchemy 中获取平均计数? 我尝试了很多东西,但都失败了。 代码:

month = sqlalchemy.func.date_trunc('month', Complaint.date)
records_count = sqlalchemy.sql.func.count(ClientGroupRecord.id)
complained_clients = session.query(Friend, records_count.label('count'), month). \
    filter(Friend.friend_id == friend_id). \
    join(Complaint, Complaint.friend == Friend.friend_id). \
    join(ClientGroup, Complaint.client_group == ClientGroup.client_group_id). \
    join(ClientGroupRecord, ClientGroup.client_group_id == ClientGroupRecord.client_group_id). \
    join(Client, Client.client_id == ClientGroupRecord.client_id). \
    group_by(month, Friend.friend_id)

records_avg = sqlalchemy.sql.func.avg(records_count)

result = ???

result 中,我不需要Friend,但希望在列上使用avg,该列标记为count,按month 列分组。

【问题讨论】:

如果您提供一些您所做的尝试,通常有助于获得正确的答案。 相关:***.com/questions/33826441/… 【参考方案1】:

一个选项是使用窗口函数,如果您的 DBMS 支持它们 - 基于 date_trunc 的使用我假设您使用的是 PostgreSQL。这样做的原因是在 GROUP BY 生成组行之后评估窗口函数。所以将计数包装在AVG(...) OVER () 中,其中窗口是整个结果集:

from sqlalchemy import func

month = func.date_trunc('month', Complaint.date)
records_count = func.count(ClientGroupRecord.id)
# Create a window of the whole set of results
records_avg = func.avg(records_count).over()

complained_clients = session.query(records_count.label('count'),
                                   records_avg.label('avg'),
                                   month.label('month')). \
    select_from(Friend). \
    join(Complaint, Complaint.friend == Friend.friend_id). \
    join(ClientGroup, Complaint.client_group == ClientGroup.client_group_id). \
    join(ClientGroupRecord, ClientGroup.client_group_id == ClientGroupRecord.client_group_id). \
    join(Client, Client.client_id == ClientGroupRecord.client_id). \
    filter(Friend.friend_id == friend_id). \
    group_by(month). \
    all()

请注意,Friend 已从 query(...) 移动到显式用作与 Query.select_from() 的第一个连接的左侧。即使您只选择具有特定 ID 的朋友,也无需在 GROUP BY 子句中使用 Friend.id

如果您对每月计数根本不感兴趣,而只想要平均值,那么更传统的subquery approach 也一样好:

from sqlalchemy import func

month = func.date_trunc('month', Complaint.date)
records_count = func.count(ClientGroupRecord.id)

complained_clients = session.query(records_count.label('count')). \
    select_from(Friend). \
    join(Complaint, Complaint.friend == Friend.friend_id). \
    join(ClientGroup, Complaint.client_group == ClientGroup.client_group_id). \
    join(ClientGroupRecord, ClientGroup.client_group_id == ClientGroupRecord.client_group_id). \
    join(Client, Client.client_id == ClientGroupRecord.client_id). \
    filter(Friend.friend_id == friend_id). \
    group_by(month). \
    subquery()

result = session.query(func.avg(complained_clients.c.count)).scalar()

...或使用窗口方法:

from sqlalchemy import func

month = func.date_trunc('month', Complaint.date)
records_count = func.count(ClientGroupRecord.id)
# Create a window of the whole set of results
records_avg = func.avg(records_count).over()

# Windows are evaluated for each row, but here we have a single window spanning
# the entire result, so the use of DISTINCT collapses this to a single value.
# Knowing what the query does LIMIT 1 / FETCH FIRST 1 ROW ONLY would work as well.
result = session.query(records_avg.label('avg')). \
    select_from(Friend). \
    join(Complaint, Complaint.friend == Friend.friend_id). \
    join(ClientGroup, Complaint.client_group == ClientGroup.client_group_id). \
    join(ClientGroupRecord, ClientGroup.client_group_id == ClientGroupRecord.client_group_id). \
    join(Client, Client.client_id == ClientGroupRecord.client_id). \
    filter(Friend.friend_id == friend_id). \
    group_by(month). \
    distinct(). \
    scalar()

【讨论】:

以上是关于如何使用 sqlalchemy 计算平均数?的主要内容,如果未能解决你的问题,请参考以下文章

如何根据平均海平面计算海拔高度

如何使属性比较能够编译为 SQLAlchemy 中的 SQL 表达式?

如何在单元测试中计算 sqlalchemy 查询

如何使用 sqlalchemy 编写自己的聚合函数?

python flask-sqlalchemy如何设置使自动建的mysql表字符集charset为utf8

试图在 Flask-SQLAlchemy 中使查询不区分大小写 [重复]