简体   繁体   English

SQLAlchemy:如何正确使用 group_by() (only_full_group_by)?

[英]SQLAlchemy: How to use group_by() correctly (only_full_group_by)?

I'm trying to use the group_by() function of SQLAlchemy with the mysql+mysqlconnector engine:我正在尝试将 SQLAlchemy 的group_by() functionmysql+mysqlconnector引擎一起使用:

rows = session.query(MyModel) \
        .order_by(MyModel.published_date.desc()) \
        .group_by(MyModel.category_id) \
        .all()

It works fine with SQLite, but for MySQL I get this error:它适用于 SQLite,但对于 MySQL 我收到此错误:

[42000][1055] Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column '...' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

I know how to solve it in plain SQL , but I'd like to use the advantages of SQLAlchemy.我知道 如何用普通的 SQL 解决它,但我想利用 SQLAlchemy 的优点。

What's the proper solution with SQLAlchemy? SQLAlchemy 的正确解决方案是什么?

Thanks in advance提前致谢

One way to form the query with well defined behaviour would be to use a LEFT JOIN , looking for MyModel rows per category_id that have no matching row with greater published_date :形成具有明确定义的行为查询的一种方法是使用LEFT JOIN ,查找每个category_idMyModel行,这些行没有匹配的行具有更大的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()

This will work in about any SQL DBMS.这将适用于任何 SQL DBMS。 In SQLite 3.25.0 and MySQL 8 (and many others) you could use window functions to achieve the same:在 SQLite 3.25.0 和 MySQL 8 (以及许多其他)中,您可以使用 window 函数来实现相同的目的:

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()

Of course you could use GROUP BY as well, if you then use the results in a join:当然,您也可以使用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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM