SQLAlchemy получает последние строки с определенного значения

#python #postgresql #sqlalchemy

#python #postgresql #sqlalchemy

Вопрос:

Я ищу способ получить все строки с момента последнего добавления определенного значения в базу данных. Например:

  -------- -------- --------  
| created| status |   my_id|
 -------- -------- -------- 
| ...    | success|       3|
| ...    | fail   |       3|
| ....   | success|       3|
| ....   | fail   |       3|
| ....   | fail   |       3|
 --------|-------- -------- 
 

Учитывая следующую таблицу, мой запрос извлечет последние две строки, например. «дайте мне последние строки с тех пор, как я в последний раз видел статус успеха»

Угловые случаи: если нет случая успеха, тогда должны быть возвращены все строки. Если последняя строка выполнена успешно, тогда верните nothing или None или что-то в этом роде.

Я не знаю, с чего начать с этого.. Я не могу упорядочить по дате, так как это испортило бы порядок. Выполнение этого в одном запросе было бы самым элегантным, что-то вроде

 #Get the last success ?
subq = (db.session.query(MyObject.status, MyObject.created, MyObject.my_id).group_by(my_id).filter_by(status=="success").order_by(created.desc)
 .subquery())
(db.session.query(MyObject).join(
    subq, #Last success
    and_(MyObject.created >= sub.c.created)
    ).filter_by(status=="fail").all())
 

РЕДАКТИРОВАТЬ: созданный имеет следующую форму: created = Column(types.DateTime, nullable=False, default=datetime.utcnow)

Вот выдержка из таблицы базы данных, показывающая некоторые значения:

 id  created             status  my_id
1   2020-11-26 16:09:03 failed  3
2   2020-11-26 16:12:03 failed  3
3   2020-11-26 16:15:03 failed  3
4   2020-11-26 16:18:04 failed  3
5   2020-11-26 16:21:04 failed  3
6   2020-11-26 16:24:04 failed  3
7   2020-11-26 16:27:04 failed  3
8   2020-11-26 16:30:05 failed  3
9   2020-11-26 16:33:00 failed  3
10  2020-11-26 16:36:00 failed  3
11  2020-11-26 16:39:01 failed  3
12  2020-11-26 16:42:01 failed  3
13  2020-11-26 16:45:01 failed  3
14  2020-11-26 16:48:01 failed  3
15  2020-11-26 16:51:02 failed  3
16  2020-11-26 16:54:02 failed  3
17  2020-11-26 16:57:02 failed  3
18  2020-11-26 17:00:08 failed  3
 

ПРАВКА2:

Я обработал запрос, когда мы уверены, что где-то там есть успех:

 subq = db.session.query(MyObj).filter_by(status="success", my_id=3). order_by (MyObj.id.desc()).limit(1).subquery("t2"))
q = MyObj.query.join(subq, and_(MyObj.status=="failed", MyObj.id > subq.c.id)).all()
 

Однако это не решает проблему «все сбой»..

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

1. Гарантированы ли значения created для строк после самого последнего успеха>= самая последняя дата успеха? (и это created дата или дата-время)? Или мы можем полагаться только на порядок вставки?

2. @snakecharmerb ответ на ваш первый вопрос: «да, так думаю». По крайней мере, такова идея. создано текущее время. Вы также можете полагаться на то, что новые идентификаторы больше, чем старые, для определения приоритета. Я обновил вопрос, пытаясь уточнить

Ответ №1:

Я думаю, что что-то подобное должно сработать

 subq = (session.query(sa.func.coalesce(sa.func.max(MyObject.created), dt.datetime.min))
               .filter_by(status='success').scalar())

q = (session.query(MyObject)
            .filter(MyObject.created >= subq)
            .filter(MyObject.status == 'failed'))
 

В подзапросе мы возвращаем наибольшую дату «успеха», используя MAX(created) . Если нет строки «success», то COALESCE datetime.datetime.min вместо этого предоставляет. Мы возвращаем a scalar , чтобы мы могли сравнить значение в фильтре.