SQLAlchemy在INSERT... ON CONFLICT中"排除"了PostgreSQL命名空间

12

我无法找到通过SQLAlchemy执行PostgreSQL INSERT .. ON UPDATE的方法。是否有一种方法可以对多行进行操作,同时对整个数据执行操作?

我试图使用从Pandas数据帧中获取的值进行upsert:

for insert_values in df.to_dict(orient='records'):
    insert_statement = sqlalchemy.dialects.postgresql.insert(orders_to_channels).values(insert_values)
    upsert_statement = insert_statement.on_conflict_do_update(
        constraint='orders_to_channels_pkey',
    set_=insert_values
    conn.execute(upsert)

这是按行处理的,每行都单独处理 - 运行非常缓慢(7000行需要20分钟)。 有没有一种方法可以通过单个SQL语句执行此操作?

我正在寻找某种机会将参数传递给更新语句的部分,例如{'column_name':'excluded .column_name'},其中“排除”不会被解析为字符串值的一部分,而是作为SQL文字处理。有方法可以做到这一点吗?

1个回答

23
使用 excluded 这个特殊别名来操作 postgresql.dml.Insert 对象。
insert_statement = sqlalchemy.dialects.postgresql.insert(orders_to_channels)
upsert_statement = insert_statement.on_conflict_do_update(
    constraint='orders_to_channels_pkey',
    set_={ 'column_name': insert_statement.excluded.column_name }
)
insert_values = df.to_dict(orient='records')
conn.execute(upsert_statement, insert_values)

请注意,psycopg2的executemany()本质上等同于在循环中使用execute(),因此您可能看不到预期的性能提升。您可以尝试使用"多个值"语法

insert_values = df.to_dict(orient='records')
insert_statement = sqlalchemy.dialects.postgresql.insert(orders_to_channels).values(insert_values)
...

但是,可能并不会更快


1
如果您想要整个内容插入,请更改相应的行以设置_set=insert_statement.excluded。 - FelixHJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接