【问题标题】:Sqlalchemy get results in the same orderSqlalchemy 以相同的顺序获取结果
【发布时间】:2015-03-29 06:19:13
【问题描述】:

我正在使用这个查询

users = User.query.filter(User.id.in_(user_ids)).all()

我想以与user_ids 相同的顺序获取users。无论如何我可以直接在查询中执行此操作还是必须再次对其进行排序?另外,如果我必须再次对其进行排序,那么基于另一个 ID 列表对对象列表进行排序的 Pythonic 方式是什么。

【问题讨论】:

  • 好吧,我找到了排序它的pythonic方式。 users.sort(key=lambda x: user_ids.index(x.id)) 但仍在寻找是否可以直接在查询中进行
  • 所以您的user_ids 具有任意顺序(不一定已排序),并且您想根据User.id 列和user_ids 列表对SQL 结果进行排序? IE。不只是ORDER BY "User.id"?
  • 好吧,除非您添加.order_by() 子句,否则结果将按插入顺序排列。 如果您的user_ids 已经排序,那么添加.order_by(User.id) 子句显然与user_ids 排序具有相同的效果(忽略排序细节)。但如果不是,并且您仍然想按它排序,那么直接在 SQL 中执行会非常复杂,所以我会在 Python 中对它们进行排序。
  • 不客气。我假设在 SQL 中执行此操作可以通过使用hybrid properties 来实现,但我想这可能以跨数据库可移植方式实现相当棘手。
  • 如果将 MySQL 计入...

标签: python list sorting sqlalchemy


【解决方案1】:

这在 PostgreSQL 9.4+ 和 SQLAlchemy 0.9.7+ 中是非常有可能的,虽然丑陋。基本上我们构建一个 id -> ordinal 的映射,然后使用 JSONB -> 运算符查找每个用户 id 的序数(-> 需要 TEXT 用于 JSON 键

from sqlalchemy.sql.postgresql import JSONB, TEXT
from sqlalchemy.sql import cast

id_order = { str(v): k for k, v in enumerate(user_ids) }
users = User.query.filter(User.id.in_(user_ids)).\
    order_by(cast(id_order, JSONB)[cast(User.id, TEXT)])

这将创建类似于

的SQL ORDER BY
ORDER BY CAST('{"1": 2, "3": 0, "2": 1}' AS JSONB) ->
         CAST(user.id AS TEXT)

对于其他数据库,只需在客户端对其进行排序 - 尽管这意味着您无法浏览结果。

在客户端排序的有效代码是:

id_order = { v: k for k, v in enumerate(user_ids) }
users = sorted(users, key=lambda u: id_order.get(u.id))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-26
    • 1970-01-01
    • 1970-01-01
    • 2018-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-20
    相关资源
    最近更新 更多