Использование 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
и т.п.