如何获取最后一条记录

108

我需要从数据库中获取最后一条记录。我正在使用SQLAlchemy。 目前,我的做法是这样的:

obj = ObjectRes.query.all()
return str(obj[-1].id)

但是这个查询太重了。我如何更好地获取最后一条记录?


"最后"在这里可以用一个明确的定义来解释。在具有并发更新的系统中,最近分配的ID和最近提交的ID可能不相同。例如,事务A分配了ID 42,事务B分配了ID 43,事务B提交,然后事务A提交。哪一个是“最后”? - snakecharmerb
4个回答

218

请看Query.first()。如果在正确的列上指定了排序,则第一个将是最后一个。示例如下:

obj = session.query(ObjectRes).order_by(ObjectRes.id.desc()).first()

7
我收到一个警告,使用它时会出现警告信息 SAWarning: Can't resolve label reference '-id'; converting to text() (this warning may be suppressed after 10 occurrences)。在使用过程中需要将标签引用'-id'转换为文本形式来解决这个问题。这个警告可能会在出现10次后被隐藏。 - Shift 'n Tab
4
现在这已经成为一个错误;我使用了Model.query.order_by(-Model.field_name).first()来检索所需的对象。 - Pratik K.
4
这个代码实际上是获取查询结果集中的所有值,再弹出第一个值(即非常低效),还是会像幕后做一些像ORDER BY desc LIMIT 1这样的智能操作? - Adam Hughes
@AdamHughes,你可以使用.limit()修饰符来指定,例如session.query(ObjectRes).order_by(ObjectRes.id.desc()).limit(1)。 - Kyle Meador

9
有时候重述简单的东西会很困难:
SELECT * FROM ObjectRes WHERE id IN (SELECT MAX(id) FROM ObjectRes)

但这个方法对我有效:

session.query(ObjectRes).filter(ObjectRes.id == session.query(func.max(ObjectRes.id)))

4

不要忘记在需要的情况下禁用现有的排序

在我的情况下,我有动态有序关系:

class Match:
  ...
  records = relationship("Record", backref="match", lazy="dynamic", order_by="Record.id")

当我尝试接受答案时,我得到了第一条记录,而不是最后一条,因为ORDER BY被应用了两次,破坏了结果。

根据文档

通过传递None可以抑制所有已存在的 ORDER BY 设置。

所以解决方案将是:

match = db_session.query(Match).first()
last_record = match.records.order_by(None).order_by(Record.id.desc()).first()

1

这个答案修改了其他答案,以允许在不知道主键名称的情况下进行操作。

from sqlalchemy.inspection import inspect
# ...
def last_row(Table: type, *, session): # -> Table
    primary_key = inspect(Table).primary_key[0].name # must be an arithmetic type
    primary_key_row = getattr(Table, primary_key)
    # get first, sorted by negative ID (primary key)
    return session.query(Table).order_by(-primary_key_row).first()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接