首页 > 解决方案 > 如何使用 max(date) 和 SQLAlchemy 选择最新的对象

问题描述

正如我在回答中提到的,这是错误的方法。

我的声明:

db.session.query(
  m.SiteServicePrice, func.max(m.SiteServicePrice.created).label('latest')).filter(
    m.SiteServicePrice.site_id == 2001).group_by(m.SiteServicePrice.service_id).all()

我想取回 m.SiteServicePrice 对象列表,而不是元组列表。

这个:

[<SiteServicePrice(site_id:2001 service_id:12 created:2019-01-30 03:25:31)>,
 <SiteServicePrice(site_id:2001 service_id:21 created:2019-01-30 03:25:31)>,
 <SiteServicePrice(site_id:2001 service_id:37 created:2019-01-30 03:25:31)>] 

而不是这个:

[(<SiteServicePrice(site_id:2001 service_id:12 created:2019-01-30 03:25:31)>, datetime.datetime(2020, 5, 28, 22, 31, 35)),
 (<SiteServicePrice(site_id:2001 service_id:21 created:2019-01-30 03:25:31)>, datetime.datetime(2020, 5, 28, 22, 31, 54)),
 (<SiteServicePrice(site_id:2001 service_id:37 created:2019-01-30 03:25:31)>, datetime.datetime(2020, 5, 28, 22, 32, 15)))] 

有没有办法将其保留func.max(m.SiteServicePrice.created)为查询的一部分,并指示 SQLAlchemy 不要将其包含在结果中?

我知道我可以使用列表理解或其他方式从结果中提取 m.SiteServicePrice 对象,但我很好奇是否有办法使用 SQLAlchemy 来做到这一点。

标签: pythonsqlsqlalchemy

解决方案


原来我原来的 SQL 查询和 SQLAlchemy 语句不正确。

原始sql查询:

select 
  max(created), 
  created, 
  service_id, c_price, s_price 
from 
  site_service_prices 
where 
  site_id = 2001 
group by service_id;

在这里,我不包括selectin 中的所有键group by。MySQL 和 MariaDB 不会将此视为错误,它确实如此。MariaDB 知识库的解释

latest使用 max(date_field) 从查询中获取项目列表,需要子查询。

这是正确的查询:

   1 SELECT
   2   id, site_id, service_id, created
   3 FROM
   4   site_service_prices join(
   5     SELECT
   6       site_id, service_id, max(created) AS created
   7     FROM
   8       site_service_prices
   9     WHERE
  10       site_id = 1
  11     GROUP BY
  12       site_id, service_id
  13   ) t2
  14 USING (
  15   site_id, service_id, created
  16 );

这就是 SQLAlchemy 查询的样子:

 # create a subquery with IDs and max date
 sq = db.session.query(
         m.SiteServicePrice.service_id.label('service_id'),
         func.max(m.SiteServicePrice.created).label('created')).filter(
               m.SiteServicePrice.site_id == 1).group_by(
                   m.SiteServicePrice.service_id).subquery()
 # join with subquery
 db.session.query(m.SiteServicePrice).join(sq,
     and_(m.SiteServicePrice.service_id == sq.c.service_id,
          m.SiteServicePrice.created == sq.c.created)).filter(
              m.SiteServicePrice.site_id == 1).order_by(
                  m.SiteServicePrice.created.desc()).all()

推荐阅读