【问题标题】:SQLAlchemy group by day in timestamp columnSQLAlchemy 在时间戳列中按天分组
【发布时间】: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。

【问题讨论】:

    标签: python sql sqlalchemy


    【解决方案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)
    

    【讨论】:

      猜你喜欢
      • 2013-01-24
      • 1970-01-01
      • 2015-02-12
      • 2018-06-03
      • 2021-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多