SQLAlchemy 在时间戳列中按天分组

Posted

技术标签:

【中文标题】SQLAlchemy 在时间戳列中按天分组【英文标题】:SQLAlchemy group by day in timestamp column 【发布时间】:2022-01-16 19:45:10 【问题描述】:

我在 SQLAlchemy 中定义了一个 ORM(模型),如下所示:

class StoreView(Base):
    __tablename__ = 'store_views'

    id = Column(Integer, primary_key=True)
    store_id = Column(Integer)
    started_from = Column(TIMESTAMP)
    end_to = Column(TIMESTAMP)
    average_watch_time = Column(Float)
    total_watch_time = Column(Float)
    total_views = Column(Float)

我计划获取每天所有视图的总和,并尝试根据它们的 end_to 对结果进行分组。我在 sqlalchemy 中使用了以下查询:

result = session.query(
                StoreView
                ).filter(
                    StoreView.started_from > from_date,
                    StoreView.end_to < to_date,
                    StoreView.store_id==5
                ).group_by( sa.func.year(StoreView.end_to), sa.func.month(StoreView.end_to)).all()

但是这个查询会抛出这个错误:

(psycopg2.errors.UndefinedFunction) function year(timestamp without time zone) does not exist
HINT:  No function matches the given name and argument types. You may need to add explicit type casts.

我在我的模型中使用时间戳,但由于某种原因我不打算更改它。我唯一能做的就是修改查询。 SQLAlchemy 已连接到 AWS Redshift。

【问题讨论】:

【参考方案1】:

如果您想在 Postgresql 中按每天的查看次数进行分组,查询将如下所示(省略WHERE 子句):

SELECT end_to::date AS date, COUNT(*) AS views    
FROM store_views    
GROUP BY end_to::date    
ORDER BY date DESC;

处理时间戳的技巧是将其转换为日期类型,这会将值截断为日期部分。在 SQLAlchemy 中,等效代码是

with Session() as s:    
    result = s.query(    
        sa.cast(StoreView.end_to, sa.Date).label('date'),    
        sa.func.count().label('views'),    
    ).filter(    
    ).group_by(    
        sa.cast(StoreView.end_to, sa.Date),    
    ).order_by(    
        sa.text('date desc')    
    )    
    for row in result:    
        print(row) 

产生类似的值

(datetime.date(2021, 5, 4), 1)
(datetime.date(2021, 5, 3), 1)
(datetime.date(2021, 5, 2), 2)
...

等效的 SQLAlchemy 2.0 样式查询将是

with Session() as s:
    q = sa.select(
        sa.cast(StoreView.end_to, sa.Date).label('date'),
        sa.func.count().label('views'),
    ).where(
        StoreView.started_from > from_date,
        StoreView.end_to < to_date,
        StoreView.store_id == 5,
    ).group_by(
        sa.cast(StoreView.end_to, sa.Date),
    ).order_by(
        sa.text('date desc')
    )
    result = s.execute(q)

【讨论】:

以上是关于SQLAlchemy 在时间戳列中按天分组的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Postgres 在 Rails 中按天对记录进行分组

如何使用 SQL Server 在此查询中按天对结果进行分组?

如何在另一列中按条件分组的列中查找下一个日期?

如何在 PL/SQL 中按每天分组?

窗口函数,尝试从连接表中的列中按 created_at 排序而不分组

在一列中按多个值分组