如何在 psycopg2 中使用 UPDATE/DELETE WHERE CURRENT OF?

How to use UPDATE/DELETE WHERE CURRENT OF in psycopg2?

我在 PostgreSQL 中使用服务器端游标和 psycopg2,基于

with conn.cursor(name='name_of_cursor') as cursor:
    query = "SELECT * FROM tbl FOR UPDATE"
    cursor.execute(query)
    for row in cursor:
        # process row

在处理每一行时,我想使用 PostgreSQL 的 UPDATE tbl SET ... WHERE CURRENT OF name_of_cursor (docs) 更新行中的几个字段,但似乎,当 for 循环进入并且 row 已设置,服务器端游标的位置在不同的记录中,因此虽然我可以 运行 命令,但更新了错误的记录。

如何确保结果迭代器与光标位于相同的位置? (也最好以一种不会使循环比使用 ID 更新更慢的方式)

更新不同记录的原因是因为 psycopg2 在内部执行 FETCH FORWARD 1000(或任何默认块大小),将光标定位在块的末尾。您可以通过一次获取一条记录来覆盖它:

updcursor = conn.cursor()
with conn.cursor(name='name_of_cursor') as cursor:
    cursor.itersize = 1  # to make server-side cursor be in the same position as the iterator
    cursor.execute('SELECT * FROM tbl FOR UPDATE')
    for row in cursor:
        # process row...
        updcursor.execute('UPDATE tbl SET fld1 = %s WHERE CURRENT OF name_of_cursor', [val])

上面的代码片段将更新正确的记录。请注意,您不能使用相同的光标进行选择和更新,它们必须是不同的光标。

性能

将 FETCH 大小减小到 1 会大大降低检索性能。如果您从与 PostgreSQL 服务器不同的主机迭代大型数据集(这可能是您正在搜索服务器端游标的情况),我绝对不建议使用此技术。

我最终使用了将记录导出到 CSV 的组合,然后稍后使用 COPY FROM(使用函数 copy_expert)导入它们。