繁体   English   中英

更新 .. 使用 SqlAlchemy 和 PostgreSQL 限制 1

[英]UPDATE .. LIMIT 1 with SqlAlchemy and PostgreSQL

使用 SqlAlchemy,是否可以构建一个只更新第一个匹配行的查询?

就我而言,我需要更新最新的日志条目:

class Log(Base):
    __tablename__ = 'logs'
    id = Column(Integer, primary_key=True)
    #...
    analyzed = Column(Boolean)

session.query(Log)  \
    .order_by(Log.id.desc())  \
    .limit(1)  \
    .update({ 'analyzed': True })

结果是:

InvalidRequestError: 当调用 limit() 时无法调用 Query.update()

这是有道理的,因为UPDATE ... LIMIT 1是一个仅限 MySQL 的功能(这里给出了解决方案)

但是我如何用 PostgreSQL 做同样的事情? 可能,使用子查询方法

子查询配方是正确的方法,现在我们只需要使用 SqlAlchemy 构建这个查询。

让我们从子查询开始:

sq = ssn.query(Log.id)  \
    .order_by(Log.id.desc())  \
    .limit(1)  \
    .with_for_update()

现在将它与as_scalar()update() 文档中的示例一起使用:

from sqlalchemy import update

q = update(Log)  \
    .values({'analyzed': True})  \
    .where(Log.id == sq.as_scalar())

打印查询以查看结果:

UPDATE logs 
SET analyzed=:analyzed 
WHERE logs.id = (
    SELECT logs.id 
    FROM logs ORDER BY logs.id DESC 
    LIMIT :param_1 
    FOR UPDATE
)

享受!

添加

WHERE analyzed <> :analyzed

以防止同一行被多次更新。 或者

WHERE analyzed IS DISTINCT FROM :analyzed

如果允许NULL值。 也将相同的条件添加到外部UPDATE中,这在任何情况下几乎总是一个好主意,以避免空更新

FOR UPDATEROW SHARE锁阻塞的并发事务在第一个事务完成后立即唤醒。 由于更改的行不再通过WHERE条件,因此子查询不返回任何行并且没有任何反应

虽然后来的事务锁定了一个新行来更新......

您可以使用咨询锁来始终更新下一个未锁定的行,而无需等待。 我在链接的答案中添加了更多内容:

或者考虑PGQ来实现队列。

我的数据库不能在子查询中使用 limit - 所以我最终使用了这样的东西:

log_id = session.query(Log.id)  \
    .order_by(Log.id.desc())  \
    .limit(1)
log_id = [log.id for log in log_id]
session.query(Log).filter(Log.id.in_(log_id)).delete()

暂无
暂无

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

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