我正在尝试使用 python 3.6 将 csv(具有标题和引号字符“)复制到远程 postgres 10 服务器上的表。它是一个大型 CSV(2.5M 行,800MB),而我之前导入它变成一个数据框,然后使用 dataframe.to_sql,这非常占用内存,所以我改用 COPY。
将 COPY 与 psycopg2 或 sqlalchemy 一起使用可以正常工作,但远程服务器无法访问本地文件系统。
在终端中使用 psql 我已成功运行下面的查询来填充表。我不认为 psycopg2 或 sqlalchemy 可以使用\copy。
\copy table (col1, col2) FROM file_location CSV HEADER QUOTE '"' NULL ''
但是,当我尝试使用如下所示的单行 psql -c 命令时,它不起作用并且出现错误:
错误:COPY 引号必须是单个单字节字符。
psql -U user -h ip -d db -w pw -c "\copy table (col1, col2) FROM file_location CSV HEADER QUOTE '"' NULL ''"
你能告诉我为什么会这样吗?
这个单行 -c psql 语句使用 python 中的子进程模块比必须打开终端并执行我不确定该怎么做的命令更容易实现。如果您能提出解决方法或不同的方法,那就太好了。
====== 根据安德鲁关于转义引号字符的建议,这在命令行上有效。然而,当像下面这样在 python 中实现它时,会出现一个新错误:
/bin/sh: -c: 第 0 行:在寻找匹配的“”时出现意外的 EOF
/bin/sh: -c: 第 1 行:语法错误:意外的文件结尾
"\"\copy table (col1, col2) FROM file_location CSV HEADER QUOTE '\"' NULL ''\""
cmd = f'psql -U {user} -h {ip} -d {db} -w {pw} -c {copy_statement}'
subprocess.call(cmd, shell=True)
最佳答案
如果可以避免,请尽量不要使用 shell=True
。最好自己标记命令以帮助 sh。
subprocess.call(["psql", "-U", "{user}", "-h", "{ip}", "-d", "{db}", "-w", "{pw}", "-c", "{copy statement}"])
在这种情况下,您的复制语句可能会被逐字传递给 psql,因为没有要考虑的 shell 引用问题。 (N.B. 仍然需要为 python 引用这个,所以字符串将保持原样)。
如果你仍然想使用 shell=True
那么你必须为 python 和 shell 转义字符串
"\"\copy table (col1, col2) FROM file_location CSV HEADER QUOTE '\\\"' NULL ''\""
将在 python 中创建一个字符串
"\copy table (col1, col2) FROM file_location CSV HEADER QUOTE '\"' NULL ''\"
这是我们首先发现我们的 shell 需要的东西!
编辑(澄清评论中的内容):
subprocess.call
,当不使用 shell=True
时,接受一个可迭代的参数。
所以你可以
psql_command = "\"\copy table (col1, col2) FROM file_location CSV HEADER QUOTE '\\\"' NULL ''\""
# user, hostname, password, dbname all defined elsewhere above.
command = ["psql",
"-U", user,
"-h", hostname,
"-d", dbname,
"-w", password,
"-c", psql_command,
]
subprocess.call(command)
参见 https://docs.python.org/2/library/subprocess.html#subprocess.call或 https://docs.python.org/3/library/subprocess.html#subprocess.call
额外编辑:- 请注意,为避免 shell 注入(inject),您应该使用此处描述的方法。请参阅 https://docs.python.org/2/library/subprocess.html#frequently-used-arguments 的警告部分
关于Python psql\copy CSV 到远程服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46758865/