Как выбрать последние объекты, используя max (date) с помощью SQLAlchemy

#python #sql #sqlalchemy

#python #sql #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.

Ответ №1:

Оказывается, мой исходный 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;
  

Здесь я не включаю все ключи из select in 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()
  

Ответ №2:

Просто повторите их с помощью простого цикла for и сохраните в другом массиве.

Комментарии:

1. Я знаю, что могу это сделать. Я даже упомянул об этом в конце своего вопроса. Я хотел бы знать, есть ли способ sqlalchemy делать то, что я хочу.