我正在尝试使用COPY命令通过Python将文件中的数据插入到PGSQL中。当目标表为空或我提前确保没有唯一的密钥冲突时,这非常有效:
cmd = ("COPY %s (%s) FROM STDIN WITH (FORMAT CSV, NULL '_|NULL|_')" %
(tableName, colStr))
cursor.copy_expert(cmd, io)
但是,我希望能够在不先清空表的情况下执行此COPY命令。有没有办法用SQL COPY进行'INSERT或UPDATE'类型操作?
答案 0 :(得分:5)
不直接通过复制命令。
然而,您可以创建一个临时表,使用copy命令填充该表,然后从中进行插入和更新。
-- Clone table stucture of target table
create temporary table __copy as (select * from my_schema.my_table limit 0);
-- Copy command goes here...
-- Update existing records
update
my_schema.my_table
set
column_2 = __copy.column_2
from
__copy
where
my_table.column_1 = __copy.column_1;
-- Insert new records
insert into my_schema.my_table (
column_1,
column_2
) (
select
column_1,
column_2
from
__copy
left join my_schema.my_table using(column_1)
where
my_table is null
);
您可以考虑在使用数据填充后在__copy上创建索引以加快更新查询。
答案 1 :(得分:1)
考虑使用临时表作为接收csv文件数据的登台表。然后,使用Postgres'运行追加到决赛桌。 CONFLICT (colname) DO UPDATE ...
。适用于9.3+版本。见docs。请注意,特殊的排除表用于引用最初建议插入的值。
另外,假设您使用pyscopg2,请考虑使用sql.Identifier()安全地绑定表名或列名等标识符。但是,您需要分解 colStr 以包装单个项目:
from psycopg2 import sql
...
cursor.execute("DELETE FROM tempTable")
conn.commit()
cmd = sql.SQL("COPY {0} ({1}) FROM STDIN WITH (FORMAT CSV, NULL '_|NULL|_'))")\
.format(sql.Identifier(temptableName),
sql.SQL(', ').join([sql.Identifier('col1'),
sql.Identifier('col2'),
sql.Identifier('col3')]))
cursor.copy_expert(cmd, io)
sql = "INSERT INTO finalTable (id_column, Col1, Col2, Col3)" + \
" SELECT id_column, Col1, Col2, Col3 FROM tempTable t" + \
" ON CONFLICT (id_column) DO UPDATE SET Col1 = EXCLUDED.Col1," + \
" Col2 = EXCLUDED.Col2," + \
" Col3 = EXCLUDED.Col3 ...;"
cursor.execute(sql)
conn.commit()
答案 2 :(得分:0)
参考PostgreSQL文档,您无法将数据添加到现有表中: https://www.postgresql.org/docs/9.6/static/sql-copy.html
COPY FROM将数据从文件复制到表格(将数据附加到 表格中已有的内容)
所以我认为你在某处有另一个错误。当您尝试在表中插入第二次数据时,能否向我们提供有关您从PostgreSQL获得的消息的更多详细信息?