Сохранить вывод PL / pgSQL из PostgreSQL в файл CSV - PullRequest
802 голосов
/ 05 октября 2009

Какой самый простой способ сохранить вывод PL / pgSQL из базы данных PostgreSQL в файл CSV?

Я использую PostgreSQL 8.4 с плагином pgAdmin III и PSQL, откуда я запускаю запросы.

Ответы [ 17 ]

1209 голосов
/ 05 октября 2009

Хотите ли вы получить полученный файл на сервере или на клиенте?

Серверная сторона

Если вы хотите что-то простое для повторного использования или автоматизации, вы можете использовать встроенную в Postgresql команду COPY . например,

Copy (Select * From foo) To '/tmp/test.csv' With CSV DELIMITER ',';

Этот подход полностью работает на удаленном сервере - он не может записывать на ваш локальный ПК. Он также должен запускаться как «суперпользователь» Postgres (обычно называемый «root»), потому что Postgres не может остановить его, делая неприятные вещи с локальной файловой системой этого компьютера.

Это на самом деле не означает, что вы должны быть подключены как суперпользователь (автоматизация, которая будет представлять угрозу безопасности другого типа), потому что вы можете использовать параметр SECURITY DEFINER для CREATE FUNCTION чтобы создать функцию, которая работает так, как если бы вы были суперпользователем .

Важнейшей частью является то, что ваша функция предназначена для выполнения дополнительных проверок, а не просто для обхода защиты - так что вы можете написать функцию, которая экспортирует точные данные, которые вам нужны, или вы можете написать что-то, что может принимать различные варианты, такие как Пока они встречают строгий белый список. Вам нужно проверить две вещи:

  1. Какие файлы должны ли быть разрешены пользователю для чтения / записи на диск? Например, это может быть определенный каталог, а имя файла может иметь подходящий префикс или расширение.
  2. Какие таблиц должен ли пользователь иметь возможность чтения / записи в базе данных? Обычно это определяется в базе данных GRANT s, но функция теперь работает как суперпользователь, поэтому таблицы, которые обычно бывают «вне границ», будут полностью доступны. Возможно, вы не хотите, чтобы кто-то вызывал вашу функцию и добавлял строки в конец вашей таблицы «users»…

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


Клиентская сторона

Другой подход заключается в обработке файлов на стороне клиента , т. Е. В вашем приложении или скрипте. Серверу Postgres не нужно знать, в какой файл вы копируете, он просто выплевывает данные, а клиент помещает их куда-то.

Основной синтаксис для этого - команда COPY TO STDOUT, и графические инструменты, такие как pgAdmin, обернут ее для вас в приятном диалоге.

Клиент командной строки psql имеет специальную "мета-команду", называемую \copy, которая принимает все те же параметры, что и "реальная" COPY , но запускается внутри клиента:

\copy (Select * From foo) To '/tmp/test.csv' With CSV

Обратите внимание, что нет прерывающего ;, потому что метакоманды завершаются переводом строки, в отличие от команд SQL.

С документы :

Не путайте COPY с инструкцией psql \ copy. \ copy вызывает COPY FROM STDIN или COPY TO STDOUT, а затем извлекает / сохраняет данные в файле, доступном для клиента psql. Таким образом, доступность файла и права доступа зависят от клиента, а не от сервера при использовании \ copy.

Язык программирования вашего приложения может также иметь поддержку для извлечения или извлечения данных, но вы обычно не можете использовать COPY FROM STDIN / TO STDOUT в стандартном операторе SQL, потому что нет способа соединить поток ввода / вывода. PHP-обработчик PostgreSQL ( не PDO) включает в себя базовые функции pg_copy_from и pg_copy_to, которые копируют в / из массива PHP, что может быть неэффективно для больших наборов данных.

462 голосов
/ 08 августа 2012

Есть несколько решений:

1 psql команда

psql -d dbname -t -A -F"," -c "select * from users" > output.csv

Это имеет большое преимущество, так как вы можете использовать его через SSH, например ssh postgres@host command - что позволяет вам получить

2 postgres copy команда

COPY (SELECT * from users) To '/tmp/output.csv' With CSV;

3 psql интерактивно (или нет)

>psql dbname
psql>\f ','
psql>\a
psql>\o '/tmp/output.csv'
psql>SELECT * from users;
psql>\q

Все они могут быть использованы в сценариях, но я предпочитаю # 1.

4 pgadmin, но это не в сценарии.

85 голосов
/ 11 июня 2012

В терминале (при подключении к БД) установить вывод в файл cvs

1) Установите разделитель полей на ',':

\f ','

2) Установить формат вывода без выравнивания:

\a

3) Показывать только кортежи:

\t

4) Установить вывод:

\o '/tmp/yourOutputFile.csv'

5) Выполните ваш запрос:

:select * from YOUR_TABLE

6) Выход:

\o

После этого вы сможете найти свой CSV-файл в этом месте:

cd /tmp

Скопируйте его с помощью команды scp или отредактируйте с помощью nano:

nano /tmp/yourOutputFile.csv
34 голосов
/ 12 января 2013

Если вас интересуют все столбцы определенной таблицы вместе с заголовками, вы можете использовать

COPY table TO '/some_destdir/mycsv.csv' WITH CSV HEADER;

Это немного проще, чем

COPY (SELECT * FROM table) TO '/some_destdir/mycsv.csv' WITH CSV HEADER;

которые, насколько мне известно, эквивалентны.

23 голосов
/ 24 апреля 2018

CSV Экспорт унификации

Эта информация не очень хорошо представлена. Поскольку это второй раз, когда мне нужно было получить это, я помещу это здесь, чтобы напомнить себе, если ничего больше.

Действительно лучший способ сделать это (получить CSV из postgres) - использовать команду COPY ... TO STDOUT. Хотя вы не хотите делать это так, как показано в ответах здесь. Правильный способ использования команды:

COPY (select id, name from groups) TO STDOUT WITH CSV HEADER

Запомните только одну команду!

Отлично подходит для использования через ssh:

$ ssh psqlserver.example.com 'psql -d mydb "COPY (select id, name from groups) TO STDOUT WITH CSV HEADER"' > groups.csv

Отлично подходит для использования в докере по ssh:

$ ssh pgserver.example.com 'docker exec -tu postgres postgres psql -d mydb -c "COPY groups TO STDOUT WITH CSV HEADER"' > groups.csv

Это даже здорово на локальной машине:

$ psql -d mydb -c 'COPY groups TO STDOUT WITH CSV HEADER' > groups.csv

Или внутри докера на локальной машине?:

docker exec -tu postgres postgres psql -d mydb -c 'COPY groups TO STDOUT WITH CSV HEADER' > groups.csv

Или в кластере kubernetes, в докере, через HTTPS ??:

kubectl exec -t postgres-2592991581-ws2td 'psql -d mydb -c "COPY groups TO STDOUT WITH CSV HEADER"' > groups.csv

Так универсально, много запятых!

Ты хоть?

Да, вот мои заметки:

КОПИЯ

Использование /copy эффективно выполняет файловые операции в любой системе, в которой работает команда psql, как пользователь, выполняющий ее 1 . Если вы подключаетесь к удаленному серверу, просто скопировать файлы данных в системе, выполнив psql на / с удаленного сервера.

COPY выполняет файловые операции на сервере в качестве учетной записи пользователя внутреннего процесса (по умолчанию postgres), пути к файлам и разрешения проверяются и применяются соответствующим образом. При использовании TO STDOUT проверки прав доступа к файлам обходятся.

Обе эти опции требуют последующего перемещения файла, если psql не выполняется в системе, где вы хотите, чтобы результирующий CSV в конечном итоге находился. По моему опыту, это наиболее вероятный случай, когда вы в основном работаете с удаленными серверами.

Более сложно настроить что-то вроде туннеля TCP / IP через ssh на удаленную систему для простого вывода CSV, но для других форматов вывода (двоичного) может быть лучше /copy через туннельное соединение, выполни местный psql. Аналогичным образом, при большом импорте перемещение исходного файла на сервер и использование COPY, вероятно, является наиболее эффективным вариантом.

Параметры PSQL

С параметрами psql вы можете отформатировать вывод как CSV, но есть и недостатки, такие как необходимость помнить о необходимости отключить пейджер и не получать заголовки:

$ psql -P pager=off -d mydb -t -A -F',' -c 'select * from groups;'
2,Technician,Test 2,,,t,,0,,                                                                                                                                                                   
3,Truck,1,2017-10-02,,t,,0,,                                                                                                                                                                   
4,Truck,2,2017-10-02,,t,,0,,

Другие инструменты

Нет, я просто хочу вывести CSV из моего сервера без компиляции и / или установки инструмента.

22 голосов
/ 29 июня 2014

Мне пришлось использовать \ COPY, потому что я получил сообщение об ошибке:

ERROR:  could not open file "/filepath/places.csv" for writing: Permission denied

Итак, я использовал:

\Copy (Select address, zip  From manjadata) To '/filepath/places.csv' With CSV;

и он функционирует

16 голосов
/ 05 октября 2009

psql может сделать это для вас:

edd@ron:~$ psql -d beancounter -t -A -F"," \
                -c "select date, symbol, day_close " \
                   "from stockprices where symbol like 'I%' " \
                   "and date >= '2009-10-02'"
2009-10-02,IBM,119.02
2009-10-02,IEF,92.77
2009-10-02,IEV,37.05
2009-10-02,IJH,66.18
2009-10-02,IJR,50.33
2009-10-02,ILF,42.24
2009-10-02,INTC,18.97
2009-10-02,IP,21.39
edd@ron:~$

См. man psql для справки об опциях, используемых здесь.

12 голосов
/ 27 марта 2014

Я работаю над AWS Redshift, который не поддерживает функцию COPY TO.

Мой инструмент BI поддерживает CSV с разделителями табуляции, поэтому я использовал следующее:

 psql -h dblocation -p port -U user -d dbname -F $'\t' --no-align -c "SELECT * FROM TABLE" > outfile.csv
11 голосов
/ 04 ноября 2009

В pgAdmin III есть опция для экспорта в файл из окна запроса. В главном меню это Query -> Execute to file или есть кнопка, которая делает то же самое (это зеленый треугольник с синим гибким диском в отличие от простого зеленого треугольника, который просто выполняет запрос). Если вы не запускаете запрос из окна запроса, я бы сделал то, что предложил IMSoP, и использовал бы команду копирования.

9 голосов
/ 08 декабря 2018

Новая версия - PSQL 12 - будет поддерживать --csv.

psql - devel

- * 1010 CSV *

Переключение в режим вывода CSV (значения, разделенные запятыми). Это эквивалентно \ pset формату csv .


csv_fieldsep

Указывает разделитель полей, который будет использоваться в выходном формате CSV. Если символ-разделитель появляется в значении поля, это поле выводится в двойных кавычках, следуя стандартным правилам CSV. По умолчанию используется запятая.

Использование:

psql -c "SELECT * FROM pg_catalog.pg_tables" --csv  postgres

psql -c "SELECT * FROM pg_catalog.pg_tables" --csv -P csv_fieldsep='^'  postgres

psql -c "SELECT * FROM pg_catalog.pg_tables" --csv  postgres > output.csv
...