Python psql \copy CSV 到远程服务器

Python psql \copy CSV to remote server

我正在尝试将带有 python 3.6 的 csv(具有 header 和引号字符 ")复制到远程 postgres 10 服务器上的 table。这是一个大型 CSV(250 万行,800MB),虽然我之前将其导入数据框然后使用 dataframe.to_sql,但这是非常占用内存的,所以我改用 COPY。

将 COPY 与 psycopg2 或 sqlalchemy 一起使用可以正常工作,但远程服务器无法访问本地文件系统。

在终端中使用 psql 我已成功 运行 下面的查询填充 table。我不认为 psycopg2 或 sqlalchemy 可以使用 \copy。

\copy table (col1, col2) FROM file_location CSV HEADER QUOTE '"' NULL ''

然而,当我尝试使用如下所示的单行 psql -c 命令时,它不起作用并且出现错误:

错误:复制引号必须是单个 one-byte 字符。

psql -U user -h ip -d db -w pw -c "\copy table (col1, col2) FROM file_location CSV HEADER QUOTE '"' NULL ''"

你能告诉我为什么会这样吗?

这个 one-line -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[=20 的字符串文字=]

"\"\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 or https://docs.python.org/3/library/subprocess.html#subprocess.call

额外编辑:- 请注意,为避免 shell 注入,您应该使用此处描述的方法。请参阅 https://docs.python.org/2/library/subprocess.html#frequently-used-arguments

的警告部分