4

我需要将数据从一些源数据源加载到 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)

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

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

请建议一种更好的方法来执行此操作,而无需写入中间文件。

4

2 回答 2

7

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

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调用的错误可能会被管道进程吞没。

于 2014-11-03T21:26:42.387 回答
7

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

请参阅文档中的使用COPY TO和。COPY FROMpsycopg2

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

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

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

如果必须使用psql,请:

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

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

于 2014-11-04T03:50:32.000 回答