upsert change row_key(SERIAL)?

时间:2017-10-12 12:14:31

标签: postgresql

我通常使用一个函数来生成一个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
  • final_columns =数据框(df.columns),它不包含row_key或insert_timestamp(这两个都是由postgres创建的)
  • primary_key是postgres中用于防止重复的PRIMARY KEY的列

示例输出查询:

'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()

1 个答案:

答案 0 :(得分:3)

当你说 SERIAL列分配了一个新号码时我相信你的意思是即使存在冲突,序列值也会因冲突行的数量而增加。

如果是这样,这是预期的行为 - 请参阅here

解决此问题的一种方法是首先检查是否存在冲突情况(使用CTE),然后根据需要继续插入或更新。

这不会导致序列号在冲突时增加,但它不再是传统意义上的 upsert (这是一个非问题)。