我想运行一个更新语句,更改香蕉而不是苹果,每个新香蕉及其ID都在CSV文件中。
我试图查看Postgres网站,但里面的例子让我感到困惑。
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;
创建一个与现有表结构相匹配且没有约束条件的空临时表。
在Postgres 10及以下版本中,SQL COPY
需要超级用户权限才能执行。
从Postgres 11开始,还有一些预定义角色(以前称为“默认角色”)允许执行此操作。 手册:
COPY
只允许数据库超级用户或被授予pg_read_server_files
、pg_write_server_files
或pg_execute_server_program
其中之一角色的用户命名文件或命令[...]
psql元命令\copy
适用于任何数据库角色。手册:
执行客户端复制。这是运行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
的参数,而在参数中不执行变量插值或反引号扩展。
如果导入表格很大,则可能需要在会话期间暂时增加temp_buffers
(在会话中的第一件事):
SET temp_buffers = '500MB'; -- example value
给临时表添加索引:
CREATE INDEX tmp_x_id_idx ON tmp_x(id);
需要手动运行ANALYZE
,因为临时表不受自动清理/自动分析的覆盖。
ANALYZE tmp_x;
相关回答:
COPY tmp_x FROM '/absolute/path/to/file' (DELIMITER ';', HEADER TRUE, FORMAT CSV)
对我来说效果更好。请参阅(http://www.postgresql.org/docs/9.1/static/sql-copy.html)。 - taperUPDATE
语句中的 USING
替换为 FROM
后,此方法才适用于我(Postgres 9.3)。 - artmDELETE
连接时,应该使用USING
(因为FROM
关键字已在此处使用)。 - Erwin Brandstettertarget-db=> \copy source-table from 'source-table.csv' with DELIMITER ',';
进行导入步骤 - 而不是在复制之前加上反斜杠。请参见此页面。 - egeland我遇到了同样的问题,但在这个解决方案中我遇到了一些困难。由于我不是超级用户,使用copy会出错。所以我找到了另一个解决方案。
我正在使用postgresql和pgadmin4。以下是我想到的解决方案。
CREATE TABLE fruits_copy AS TABLE fruits WITH NO DATA;
将CSV文件中的数据导入新表(fruits_copy)。我使用的是pgadmin4,所以这里是如何导入细节。(可能会有所不同)。
从fruits_copy表更新fruits表。
UPDATE fruits SET banana = fruits_copy.banana FROM fruits_copy WHERE fruits.id = fruits_copy.id;
DROP TABLE fruits_copy;
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()