SQLAlchemy 在时间戳列中按天分组

SQLAlchemy group by day in timestamp column

我在 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。

如果您想在 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)