用于INSERT或UPDATE的Python PostgreSQL COPY命令(不仅仅是INSERT)

时间:2017-10-25 13:55:19

标签: python postgresql

我正在尝试使用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'类型操作?

3 个答案:

答案 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获得的消息的更多详细信息?