Один из способов сформировать запрос наибольшее-n-на-группу с четко определенным поведением состоит в использовании LEFT JOIN
для поиска MyModel
строк на category_id
, которые не имеют подходящей строкис большим published_date
:
my_model_alias = aliased(MyModel)
rows = session.query(MyModel).\
outerjoin(my_model_alias,
and_(my_model_alias.category_id == MyModel.category_id,
my_model_alias.published_date > MyModel.published_date)).\
filter(my_model_alias.id == None).\
all()
Это будет работать в любой СУБД SQL. В SQLite 3.25.0 и MySQL 8 (и многих других) вы можете использовать оконные функции для достижения того же:
sq = session.query(
MyModel,
func.row_number().
over(partition_by=MyModel.category_id,
order_by=MyModel.published_date.desc()).label('rn')).\
subquery()
my_model_alias = aliased(MyModel, sq)
rows = session.query(my_model_alias).\
filter(sq.c.rn == 1).\
all()
Конечно, вы также можете использовать GROUP BY
, если вы затем используете результаты вобъединение:
max_pub_dates = session.query(
MyModel.category_id,
func.max(MyModel.published_date).label('published_date')).\
group_by(MyModel.category_id).\
subquery()
rows = session.query(MyModel).\
join(max_pub_dates,
and_(max_pub_dates.category_id == MyModel.category_id,
max_pub_dates.published_date == MyModel.published_date)).\
all()