在SQLAlchemy中按年、月、日分组

24 投票
3 回答
24585 浏览
提问于 2025-04-15 14:02

我想要

DBSession.query(Article).group_by(Article.created.month).all()

但是这个查询不能使用

我该如何用SQLAlchemy来实现这个呢?

3 个回答

9

THC4k 的回答是有效的,但我想补充一下,query_result 需要事先排序,这样 itertools.groupby 才能按你想要的方式工作。

query_result = DBSession.query(Article).order_by(Article.created).all()

这里是 itertools.groupby 文档中的解释:

groupby() 的操作方式类似于 Unix 中的 uniq 过滤器。每当关键函数的值发生变化时,它就会生成一个新的分组(这就是为什么通常需要先用相同的关键函数对数据进行排序)。这种行为与 SQL 的 GROUP BY 不同,后者会聚合相同的元素,而不管它们的输入顺序。

17

我知道这个问题已经很久了,但为了帮助那些寻找解决方案的人,这里有另一种针对不支持像 MONTH() 这样的函数的数据库的策略:

db.session.query(sa.func.count(Article.id)).\
    group_by(sa.func.strftime("%Y-%m-%d", Article.created)).all()

基本上,这个方法是把时间戳转换成可以被分组的简化字符串。

如果你只想要最新的记录,你可以加上,比如:

    order_by(Article.created.desc()).limit(7)

按照这个方法,你可以轻松地创建像星期几这样的分组,只需省略年份和月份。

44

假设你的数据库引擎确实支持像 MONTH() 这样的函数,你可以试试下面的代码。

import sqlalchemy as sa
DBSession.query(Article).group_by( sa.func.year(Article.created), sa.func.month(Article.created)).all()

否则,你可以在Python中进行分组,像这样:

from itertools import groupby

def grouper( item ): 
    return item.created.year, item.created.month
for ( (year, month), items ) in groupby( query_result, grouper ):
    for item in items:
        # do stuff

撰写回答