如何使用Postgres中的CSV文件中的值更新选定的行?

时间:2012-01-18 12:59:56

标签: sql database postgresql file-io csv

我正在使用Postgres并希望制作一个可以从CSV文件中获取的大型更新查询,假设我有一张表(id, banana, apple)

我想运行一个更新香蕉而不是苹果的更新,每个新香蕉及其ID都将在CSV文件中。

我试着查看Postgres网站,但这些例子正在扼杀我。

2 个答案:

答案 0 :(得分:125)

我会COPY将文件放到临时表中并从那里更新实际的表。 可能看起来像这样:

CREATE TEMP TABLE tmp_x (id int, apple text, banana text); -- but see below

COPY tmp_x FROM '/absolute/path/to/file' (FORMAT csv);

UPDATE tbl
SET    banana = tmp_x.banana
FROM   tmp_x
WHERE  tbl.id = tmp_x.id;

DROP TABLE tmp_x; -- else it is dropped at end of session automatically

如果导入的表与要更新的表匹配,则可能很方便:

CREATE TEMP TABLE tmp_x AS SELECT * FROM tbl LIMIT 0;

创建一个与现有表的结构匹配的空临时表,没有约束。

权限

SQL COPY需要超级用户权限。 (The manual):

  

COPY仅允许将文件或命令命名为数据库   超级用户,因为它允许读取或写入任何文件   服务器有权访问。

psql 元命令 \copy 适用于任何数据库角色。 The manual:

  

执行前端(客户端)副本。这是一个运行的操作   SQL COPY命令,而不是服务器读取或写入   指定的文件,psql读取或写入文件并路由数据   服务器和本地文件系统之间。这意味着该文件   可访问性和权限是本地用户的权限,而不是   服务器,并且不需要SQL超级用户权限。

临时表的范围仅限于单个角色的单个会话,因此上述操作必须在同一个psql会话中执行:

CREATE TEMP TABLE ...;
\copy tmp_x FROM '/absolute/path/to/file' (FORMAT csv);
UPDATE ...;

如果您使用bash命令编写脚本,请确保将其全部包含在 psql调用中。像:

echo 'CREATE TEMP TABLE tmp_x ...; \copy tmp_x FROM ...; UPDATE ...;' | psql

通常,您需要元命令\\在psql中的psql元命令和SQL命令之间切换,但\copy是此规则的一个例外。再次手册:

  

特殊解析规则适用于\copy元命令。与大多数其他元命令不同,该行的整个剩余部分始终被视为\copy的参数,并且在参数中不执行变量插值或反引号扩展。

大表

如果import-table很大,可能需要为会话暂时增加temp_buffers(会话中的第一件事):

SET temp_buffers = '500MB';  -- example value

向临时表添加索引:

CREATE INDEX tmp_x_id_idx ON tmp_x(id);

并手动运行ANALYZE,因为autovacuum / auto-analyze不包含临时表。

ANALYZE tmp_x;

相关答案:

答案 1 :(得分:-1)

您可以尝试下面用python编写的代码,输入文件是csv文件,您要将其内容更新到表中。每行都基于逗号进行拆分,因此对于每行,row [0]是第一列下的值,row [1]是第二列下的值,等等。

    import csv
    import xlrd
    import os
    import psycopg2
    import django
    from yourapp import settings
    django.setup()
    from yourapp import models


    try:
       conn = psycopg2.connect("host=localhost dbname=prodmealsdb 
       user=postgres password=blank")
       cur = conn.cursor()

       filepath = '/path/to/your/data_to_be_updated.csv'
       ext = os.path.splitext(filepath)[-1].lower()
       if (ext == '.csv'): 
          with open(filepath) as csvfile:
          next(csvfile)
          readCSV = csv.reader(csvfile, delimiter=',')
          for row in readCSV:
              print(row[3],row[5])
              cur.execute("UPDATE your_table SET column_to_be_updated = %s where 
              id = %s", (row[5], row[3]))
              conn.commit()
          conn.close()
          cur.close()

    except (Exception, psycopg2.DatabaseError) as error:
    print(error)
    finally:
    if conn is not None:
      conn.close()