在Python中使用Postgres的COPY FROM文件查询而无需写入临时文件

use*_*637 2 python csv postgresql postgresql-copy

我需要将数据从一些源数据源加载到Postgres数据库.要执行此任务,我首先将数据写入临时CSV文件,然后使用COPY FROM查询将数据从CSV文件加载到Postgres数据库.我在Python上做了所有这些.

代码如下所示:

table_name = 'products'
temp_file = "'C:\\Users\\username\\tempfile.csv'"
db_conn = psycopg2.connect(host, port, user, password, database)
cursor = db_conn.cursor()
query = """COPY """ + table_name + """ FROM """ + temp_file + " WITH NULL AS ''; """
cursor.execute(query)
Run Code Online (Sandbox Code Playgroud)

我想避免写入中间文件的步骤.相反,我想写一个Python对象,然后使用COPY FROM file方法将数据加载到postgres数据库.

我知道这种使用psycopg2的copy_from方法的技术,该方法将数据从StringIO对象复制到postgres数据库.但是,我不能使用psycopg2是有原因的,因此,我不希望我的COPY FROM任务依赖于库.我希望它是Postgres查询,也可以由任何其他postgres驱动程序运行.

请不要写入中间文件,建议更好的方法.

Cra*_*ger 7

psycopg2集成了对COPY有线协议的支持,允许您使用COPY ... FROM STDIN/ COPY ... TO STDOUT

请参阅使用COPY TOCOPY FROMpsycopg2文档。

既然你说你不能使用 psycopg2,那你就不走运了。驱动程序必须理解COPY TO STDOUT/COPY FROM STDIN才能使用它们,或者必须提供一种将原始数据写入套接字的方法,以便您可以劫持驱动程序的网络套接字并COPY自己实现协议。为此,驱动程序特定代码是绝对需要的,不可能简单地使用 DB-API。

因此,坎普森的建议虽然通常是一个非常糟糕的主意,但似乎是您唯一的选择。

(我发布这个主要是为了确保找到这个答案但没有使用限制的其他人psycopg2做理智的事情。)

如果您必须使用psql,请:

  • subprocess模块Popen构造函数一起使用
  • 通过-qAtX-v ON_ERROR_STOP=1topsql获得理智的批处理行为。
  • 使用数组形式命令,例如['psql', '-v', 'ON_ERROR_STOP=1', '-qAtX', '-c', '\copy mytable from stdin'],而不是使用外壳。
  • 写入psql的标准输入,然后关闭它,等待psql完成。
  • 请记住捕获在命令失败时抛出的异常。让我们subprocess捕获 stderr 并将其包装在异常对象中。

它比旧式os.popen2等更安全,更清洁,更容易正确。


kha*_*son 6

您可以从脚本中调用psql命令行工具(即使用subprocess.call)并利用其\copy命令,将一个实例的输出传递给另一个实例的输入,从而避免使用临时文件.即

psql -X -h from_host -U user -c "\copy from_table to stdout" | psql -X -h to_host -U user -c "\copy to_table from stdin"

这假定表存在于目标数据库中.如果没有,则首先需要单独的命令来创建它.

另请注意,此方法的一个警告是第一次psql调用的错误可能会被管道进程吞噬.