Использование Postgres COPY FROM файлового запроса в Python без записи во временный файл

Мне нужно загрузить данные из некоторых источников данных в базу данных Postgres. Чтобы выполнить эту задачу, я сначала записываю данные во временный файл CSV, а затем загружаю данные из файла CSV в базу данных Postgres, используя запрос COPY FROM. Я делаю все это на 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 и затем загрузить данные в базу данных postgres, используя метод файла COPY FROM.

Мне известна эта техника использования метода copy_from из psycopg2, который копирует данные из объекта StringIO в базу данных postgres. Однако я не могу использовать psycopg2 по какой-то причине и, следовательно, я не хочу, чтобы моя задача COPY FROM зависела от библиотеки. Я хочу, чтобы это был запрос Postgres, который также может запускаться любым другим драйвером postgres.

Пожалуйста, посоветуйте лучший способ сделать это без записи в промежуточный файл.

2 ответа

Решение

Вы можете вызвать инструмент командной строки 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 вызов может быть поглощен процессом трубопровода.

psycopg2 имеет интегрированную поддержку COPY проводной протокол, позволяющий использовать COPY ... FROM STDIN / COPY ... TO STDOUT,

Смотрите Использование COPY TO а также COPY FROM в psycopg2 Docs.

Поскольку вы говорите, что не можете использовать psycopg2, вам не повезло. Водители должны понимать COPY TO STDOUT / COPY FROM STDIN чтобы использовать их или предоставить способ записи необработанных данных в сокет, чтобы вы могли перехватить сетевой сокет драйвера и реализовать COPY протокол сам. Для этого абсолютно необходим специальный драйвер, просто невозможно использовать DB-API.

Таким образом, предложение Хэмпсона, хотя обычно и является действительно плохой идеей, кажется, является вашей единственной альтернативой.

(Я публикую это в основном, чтобы убедиться, что другие люди, которые находят этот ответ, не имеют ограничений по использованию psycopg2 делай вменяемые вещи.)

Если вы должны использовать psql, пожалуйста:

  • Использовать subprocess модуль с Popen конструктор
  • Проходить -qAtX а также -v ON_ERROR_STOP=1 в psql чтобы получить нормальное поведение для дозирования.
  • Используйте команду формы массива, например ['psql', '-v', 'ON_ERROR_STOP=1', '-qAtX', '-c', '\copy mytable from stdin'] вместо использования оболочки.
  • Написать в psql хз, потом закрой, и жди psql заканчивать.
  • Не забудьте перехватывать исключения, возникающие при сбое команды. Позволять subprocess захватить stderr и обернуть его в объект исключения.

Это безопаснее, чище и легче получить право, чем в старом стиле os.popen2 и т.п.

Другие вопросы по тегам