我通常使用一个函数来生成一个upsert语句,将一个数据帧(逐行)提供给Postgres。这似乎按预期工作,但我注意到SERIAL列有一个新的编号分配给它们。这是期望还是我应该改变什么?所以我最早的行如第1行可能是30,128行或者现在的东西。
def create_update_query(final_columns, primary_key, table):
"""This creates an UPSERT statement to replace values if there is a conflict with the primary key"""
columns = ', '.join([f'{col}' for col in final_columns])
constraint = ', '.join([f'{col}' for col in primary_key])
placeholder = ', '.join([f'%({col})s' for col in final_columns])
updates = ', '.join([f'{col} = EXCLUDED.{col}' for col in final_columns])
query = f"""INSERT INTO {table} ({columns})
VALUES ({placeholder})
ON CONFLICT ({constraint})
DO UPDATE SET {updates};"""
query.split()
query = ' '.join(query.split())
return query
示例输出查询:
'INSERT INTO example.fact_table (report_date, employee_id, state_count, state_time) VALUES (%(report_date)s, %(employee_id)s, %(state_count)s, %(state_time)s) ON CONFLICT (report_date, employee_id) DO UPDATE SET report_date = EXCLUDED.report_date, employee_id = EXCLUDED.employee_id, state_count = EXCLUDED.state_count, state_time = EXCLUDED.state_time;'
通过以下方式将其提供给数据库:
for row in insert_values:
cursor.execute(create_update_query(final_columns, primary_key, table), row)
conn.commit()
答案 0 :(得分:3)
当你说 SERIAL列分配了一个新号码时我相信你的意思是即使存在冲突,序列值也会因冲突行的数量而增加。
如果是这样,这是预期的行为 - 请参阅here。
解决此问题的一种方法是首先检查是否存在冲突情况(使用CTE),然后根据需要继续插入或更新。
这不会导致序列号在冲突时增加,但它不再是传统意义上的 upsert (这是一个非问题)。