首页 > 解决方案 > 在 SqlAlchemy 上使用 distinct on (Postgres) 的正确方法是什么?

问题描述

我想获取具有 max(timestamp) 和按名称分组的表的所有列。

到目前为止我尝试的是: normal_query =“从表中选择 max(timestamp) 作为时间”

event_list = normal_query \
            .distinct(Table.name)\
            .filter_by(**filter_by_query) \
            .filter(*queries) \
            .group_by(*group_by_fields) \
            .order_by('').all()

我得到的查询:

SELECT  DISTINCT ON (schema.table.name) , max(timestamp)....

该查询基本上返回带有名称和时间戳的两列。

而我想要的查询:

SELECT DISTINCT ON (schema.table.name) * from table order by ....

它返回该表中的所有列。这是预期的行为,我能够得到所有的列,我怎么能在 python 中正确地得到这个语句?。基本上没有星号。有人可以帮助我吗?

标签: pythonpostgresqlsqlalchemyflask-sqlalchemy

解决方案


您似乎想要的是DISTINCT ON ... ORDER BYPostgresql 中用于选择结果(N = 1)的习语。因此,而不是仅仅分组和聚合

event_list = Table.query.\
    distinct(Table.name).\
    filter_by(**filter_by_query).\
    filter(*queries).\
    order_by(Table.name, Table.timestamp.desc()).\
    all()

这将最终选择按名称“分组”的行,具有最大的时间戳值。

大多数时候,您不想在应用程序代码中使用星号,除非您正在执行手动临时查询。星号基本上是“FROM表/关系中的所有列”,如果您添加列、重新排序等,它可能会在以后打破您的假设。

如果您想根据最终结果中的时间戳对结果行进行排序,您可以使用例如Query.from_self()将查询转换为子查询,并在封闭查询中排序:

event_list = Table.query.\
    distinct(Table.name).\
    filter_by(**filter_by_query).\
    filter(*queries).\
    order_by(Table.name, Table.timestamp.desc()).\
    from_self().\
    order_by(Table.timestamp.desc()).\
    all()

推荐阅读