0

我将 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 替换该功能,但遇到了问题。

我的表有 50 列。1 列称为 phy 是主键。

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

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

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

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 方法配置为只更新传入的列的值?如果没有,替换我原来的更新或插入功能的最佳方法是什么?

任何帮助表示赞赏!

4

1 回答 1

1

关于您的第一个代码片段,如果您反过来这样做,它应该可以工作:

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 功能,我认为您是对的 - 在字典不包含所有列的情况下,它不会按预期工作。我已经提出了改进建议的问题

作为一种解决方法,在解决此问题之前,您可以通过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)

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

于 2021-06-11T12:25:50.973 回答