PyGreSQL upsert() 需要帮助

PyGreSQL upsert() Help Needed

我将 CentOS-6 与 Python 3.8、PostgreSQL 12 和 PyGreSQL 5.2.2 一起使用。

对于旧版本,我有如下功能。那时,如果该行尚不存在,则更新会引发异常,因此在出现异常时,我会插入该行数据。

import pg
db = pg.DB(myDatabaseName, myport)
try:
   db.update(tableName, None, **rowData)
except:
   db.insert(tableName, None, **rowData)

对于我现在使用的版本,如果该行不存在,更新不会引发异常,因此我的代码不再正常运行。我正在尝试使用 upsert 替换该功能,但是 运行 遇到了问题。

我的 table 有 50 列。 1 个名为 phy 的列是主键。

我认为以下 upsert 命令会更新我在 rowData 变量中传递的列的值,而让其他列保持不变。如果这个主键没有一行数据,它会插入一行新数据。

rowData = {'phy': 1234, 'col2': 'test', 'col3': 'test'}
db.upsert(tableName, rowData)

upsert 方法正在更新 table 中的每一列。它正在执行这样的命令:

INSERT INTO tableName AS included ('phy', 'col2', col3') VALUES (1234, 'test', 'test) ON CONFLICT (phy) DO update set "col4" = excluded."col4", "col5"=excluded."col5" etc with all 50 columns listed here

有没有办法配置 upsert 方法只更新传入的列的值?如果没有,替换我原来的更新或插入功能的最佳方法是什么?

感谢任何帮助!

关于您的第一个代码片段,如果您以相反的方式进行,它应该可以工作:

try:
    db.insert(tableName, None, **rowData)
except pg.IntegrityError:
    db.update(tableName, None, **rowData)

你也可以简化这个:

try:
    db.insert(tableName, rowData)
except pg.IntegrityError:
    db.update(tableName, rowData)

也许这与使用 OID 更新的旧 PostgreSQL 版本的行为不同。

关于 upsert 功能,我认为你是对的 - 在字典不包含所有列的情况下,它不会按预期工作。我已经提交了 issue 改进建议。

作为解决方法,在解决此问题之前,您可以通过 upsert() 方法的关键字明确声明应更新哪些列。所以你可以这样做:

rowData = {'phy': 1235, 'col2': 'test2', 'col3': 'test3'}
kw = {n: n in rowData for n in db.get_attnames(tableName)}
db.upsert(tableName, rowData, **kw)

即您传递了一个字典,其中包含不属于指定 rowData 的列的 False 值。