Альтернативой решению Matteo является использование подзапроса и присоединение его к таблице, что дает результат в моем предпочтительном формате объекта sqlalchemy.orm.query.Query
. Кредит Matteo за код для подзапроса:
subq = db_session.query(User.id_, func.max(User.timestamp).label("maxtimestamp")).filter(User.timestamp < timestamp).group_by(User.id_).subquery()
q = db_session.query(User).join(subq, and_(User.id_ == subq.c.id, User.timestamp == subq.c.maxtimestamp))
Генерация SQL
Обратите внимание, что это, вероятно, менее эффективно, чем решение Matteo:
SQL, сгенерированный решением подзапроса
SELECT users.id AS users_id, users.timestamp AS users_timestamp, users.name AS users_name, users.notes AS users_notes, users.active AS users_active
FROM users JOIN (SELECT users.id AS id, max(users.timestamp) AS maxtimestamp
FROM users
WHERE users.timestamp < ? GROUP BY users.id) AS anon_1 ON users.id = anon_1.id AND users.timestamp = anon_1.maxtimestamp
SQL, сгенерированный решением Маттео:
SELECT users.id AS users_id, users.timestamp AS users_timestamp, users.name AS users_name, users.notes AS users_notes, users.active AS users_active, max(users.timestamp) AS max_1
FROM users
WHERE users.timestamp <= ? GROUP BY users.id
Предыдущее содержание этого ответа
@ Маттео Ди Наполи
Спасибо, ваш пост более или менее нужен мне. Результатом этого является sqlalchemy.util._collections.result
, который ведет себя как кортеж из того, что я вижу. В моем приложении мне нужны полные User
объекты, а не просто пары id / timestamp, поэтому для меня лучше всего подойдет:
from sqlalchemy import func
all_versions = db_session.query(User, func.max(User.timestamp)).\
filter(User.timestamp <= timestamp).\
group_by(User.id_)
Возвращая что-то вроде:
> for i in all_versions: print(i)
...
(<User "my test user v2", id 0, modified 2019-06-19 14:42:16.380381>, datetime.datetime(2019, 6, 19, 14, 42, 16, 380381))
(<User "v2", id 1, modified 2019-06-19 15:53:53.147039>, datetime.datetime(2019, 6, 19, 15, 53, 53, 147039))
(<User "a user", id 2, modified 2019-06-20 12:34:56>, datetime.datetime(2019, 6, 20, 12, 34, 56))
Затем я могу получить доступ к объектам пользователя с помощью all_versions[n][0]
или получить список с помощью l = [i[0] for i in all_versions]
(спасибо Маттео Ди Наполи за лучший синтаксис).
Идеальный конечный результат был бы, если бы я мог получить результат, который все еще будет sqlalchemy.orm.query.Query
(например, all_versions
), но с каждым элементом будет объект User
, а не sqlalchemy.util._collections.result
. Это возможно?