Сохранить вывод PL / pgSQL из PostgreSQL в файл CSV


Ответы:


1369

Вам нужен полученный файл на сервере или на клиенте?

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

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

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

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

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

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

  1. Какие файлы должны быть разрешены пользователю для чтения / записи на диске? Например, это может быть определенный каталог, а имя файла может иметь подходящий префикс или расширение.
  2. Какие таблицы должен иметь пользователь для чтения / записи в базе данных? Обычно это определяется GRANTs в базе данных, но теперь функция работает как суперпользователь, поэтому таблицы, которые обычно бывают «вне границ», будут полностью доступны. Вы, вероятно, не хотите, чтобы кто-то вызывал вашу функцию и добавлял строки в конец вашей таблицы «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, что может быть неэффективно для больших наборов данных.


131
Очевидно, что в приведенном выше примере иногда требуется, чтобы пользователь был суперпользователем, вот версия для обычных людей;) echo «COPY (SELECT * from foo) TO STOOUT с CSV HEADER» | psql -o '/tmp/test.csv' database_name
Drachenfels

10
@Drachenfels: \copyтоже работает - там, пути относительно клиента, и точка с запятой не нужна / не разрешена. Смотрите мое редактирование.
krlmlr

3
@IMSoP: Как бы вы добавили оператор COPY в функцию sql (на postgres 9.3)? Таким образом, запрос сохраняется в файле .csv?
ДЖО.

12
Похоже, \copyдолжен быть один вкладыш. Таким образом, вы не получаете красоту форматирования SQL, как вы хотите, и просто поместив копию / функцию вокруг него.
Исаакль

1
@AndreSilva Как говорится в ответе, \copyэто специальная мета-команда в psqlклиенте командной строки . Это не будет работать в других клиентах, таких как pgAdmin; у них, вероятно, будут свои собственные инструменты, такие как графические мастера, для выполнения этой работы.
IMSoP

519

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

1 psqlкоманда

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

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

2 copyкоманды postgres

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 пгадмина но это не в сценарии.


32
ИМХО первый вариант подвержен ошибкам, потому что он не включает в себя правильное экранирование запятой в экспортируемых данных.
Piohen

4
Кроме того, psql не заключает в кавычки значения ячеек, поэтому, если ЛЮБОЙ из ваших данных будет использоваться разделитель, ваш файл будет поврежден.
Cerin

7
@Cerin -t - это синоним для --tuples-only (отключить печать имен столбцов и
нижних

21
Только что проверил утверждение с запятой - это правда, метод # 1 не пропускает запятые в значениях.
MrColes

1
также используйте «\ pset footer», чтобы количество строк в файле не
зависало

94

В терминале (при подключении к БД) установите вывод в файл 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

4
и \ о, чтобы снова напечатать консоль
metdos

2
Это не будет производить CSV-файл, он будет просто записывать вывод команды в текстовый файл (который не делает его разделенным запятыми).
Руслан Кабалин

@RuslanKabalin Да, я только что заметил это и исправил инструкцию по созданию вывода через запятую (cvs)
Марцин Василук

5
Я бы улучшил этот ответ, отметив, что вывод "csv" не будет должным образом экранирован, и каждый раз, когда выполняется команда sql, результаты объединяются в выходной файл.
Дэнни Армстронг

Как насчет перевода строки в значениях поля? COPYИли \copyприближается ручку правильно (конвертировать в стандартный формат CSV); Является ли это?
Wildcard

37

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

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

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

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

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


1
Если запрос является пользовательским (IE имеет псевдонимы столбцов или объединяет разные таблицы), заголовок будет печатать псевдонимы столбцов так же, как они отображаются на экране.
Деви

34

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 с моего сервера без компиляции и / или установки инструмента.


1
Куда сохраняются результаты? Мой запрос выполняется, но файл не отображается нигде на моем компьютере. Вот что я делаю: COPY (выберите a, b из c, где d = '1'), ЧТОБЫ СОХРАНИТЬ С CSVHEADER> abcd.csv
kRazzy R

1
@kRazzyR Выходные данные отправляются на стандартный вывод команды psql, поэтому в конечном итоге все, что вы делаете с использованием стандартного вывода, - это то, куда направляются данные. В моих примерах я использую «> file.csv» для перенаправления в файл. Вы хотите убедиться, что команда находится вне сервера, отправляемого через параметр psql -c. Смотрите пример с «локальной машиной».
Джошперри

1
Спасибо за полное объяснение. Команда copy безнадежно сложна с psql. Я обычно использую бесплатный клиент базы данных (dbeaver community edition) для импорта и экспорта файлов данных. Это обеспечивает хорошие инструменты отображения и форматирования. Ваш ответ содержит отличные подробные примеры копирования с удаленных систем.
Рич Лысаковски доктор философии

24

Мне пришлось использовать \ 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;

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


17

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
Это не настоящий CSV-файл - смотрите, как он записывается, если в данных есть запятые - поэтому использование встроенной поддержки COPY предпочтительнее. Но этот общий метод удобен для быстрого экспорта из Postgres в другие форматы с разделителями, кроме CSV.
Грег Смит

17

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

PSQL - devel

--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

16

Я работаю над 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

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


Ответ IMSoP не сработал для меня, так как мне нужно было быть супер-администратором. Это сработало. Спасибо!
Майк

9

Я попробовал несколько вещей, но немногие из них смогли дать мне желаемый CSV с подробностями заголовка.

Вот что сработало для меня.

psql -d dbame -U username \
  -c "COPY ( SELECT * FROM TABLE ) TO STDOUT WITH CSV HEADER " > \
  OUTPUT_CSV_FILE.csv

9

Я написал небольшой инструмент под названием, psql2csvкоторый инкапсулирует COPY query TO STDOUTшаблон, что приводит к правильному CSV. Это интерфейс похож на psql.

psql2csv [OPTIONS] < QUERY
psql2csv [OPTIONS] QUERY

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

-h, --help           show help, then exit
--encoding=ENCODING  use a different encoding than UTF8 (Excel likes LATIN1)
--no-header          do not output a header

2
Работает отлично. Спасибо.
AlexM

6

Если у вас более длинный запрос, и вы хотите использовать psql, поместите запрос в файл и используйте следующую команду:

psql -d my_db_name -t -A -F";" -f input-file.sql -o output-file.csv

FWIW, мне пришлось использовать -F","вместо того, -F";"чтобы генерировать файл CSV, который будет правильно открываться в MS Excel
CFL_Jeff

4

Чтобы загрузить CSV-файл с именами столбцов в качестве HEADER, используйте следующую команду:

Copy (Select * From tableName) To '/tmp/fileName.csv' With CSV HEADER;

1

Я очень рекомендую DataGrip , IDE для базы данных JetBrains. Вы можете экспортировать запрос SQL в файл CSV и с легкостью настроить ssh-туннелирование. Когда документация ссылается на «набор результатов», они означают результат, возвращаемый SQL-запросом в консоли.

Я не связан с DataGrip, я просто люблю продукт!


Я предполагаю, что понижение было связано с отсутствием контекста / объяснения, поэтому я связался с документацией DataGrip. Если есть другая причина для понижения, пожалуйста, дайте мне знать. Я использовал решения CLI выше, и DataGrip намного проще для небольших запросов.
skeller88

Проблема с DataGrip заключается в том, что он надежно удерживает ваш кошелек. Это не бесплатно. Попробуйте версию сообщества DBeaver на dbeaver.io . Это многоплатформенный инструмент для баз данных FOSS для программистов SQL, администраторов баз данных и аналитиков, который поддерживает все популярные базы данных: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto и т. Д.
Рич Лысаковски PhD

Круто, я проверю это. Как насчет того, чтобы опубликовать свой комментарий как ответ?
skeller88

0

JackDB , клиент базы данных в вашем веб-браузере, делает это действительно легко. Особенно если ты на Heroku.

Это позволяет вам подключаться к удаленным базам данных и выполнять SQL-запросы к ним.

                                                                                                                                                       Источник (источник: jackdb.com )jackdb-Heroku


Как только ваша БД подключена, вы можете запустить запрос и экспортировать в CSV или TXT (см. Справа внизу).


jackdb-экспорт

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


0

По запросу @ skeller88 я публикую свой комментарий в качестве ответа, чтобы его не потеряли люди, которые не читают каждый ответ ...

Проблема с DataGrip заключается в том, что он надежно удерживает ваш кошелек. Это не бесплатно. Попробуйте версию сообщества DBeaver на dbeaver.io. Это многоплатформенный инструмент для баз данных FOSS для программистов SQL, администраторов баз данных и аналитиков, который поддерживает все популярные базы данных: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto и т. Д.

DBeaver Community Edition позволяет легко подключиться к базе данных, выполнить запросы для извлечения данных, а затем загрузить набор результатов, чтобы сохранить его в CSV, JSON, SQL или других распространенных форматах данных. Это жизнеспособный конкурент FOSS для TOAD для Postgres, TOAD для SQL Server или Toad для Oracle.

Я не имею никакого отношения к DBeaver. Мне нравится цена и функциональность, но я бы хотел, чтобы они больше открывали приложение DBeaver / Eclipse и позволяли легко добавлять аналитические виджеты в DBeaver / Eclipse, а не требовать от пользователей платить за годовую подписку для создания графиков и диаграмм непосредственно внутри приложение. Мои навыки Java-кодирования устарели, и я не хочу потратить недели на то, чтобы заново научиться создавать виджеты Eclipse, но обнаружил, что DBeaver отключил возможность добавления сторонних виджетов в DBeaver Community Edition.

Имеют ли пользователи DBeaver представление о том, как создавать аналитические виджеты для добавления в Community Edition DBeaver?


-3
import json
cursor = conn.cursor()
qry = """ SELECT details FROM test_csvfile """ 
cursor.execute(qry)
rows = cursor.fetchall()

value = json.dumps(rows)

with open("/home/asha/Desktop/Income_output.json","w+") as f:
    f.write(value)
print 'Saved to File Successfully'

3
Пожалуйста, объясните, что вы делали, редактируя ответ, избегая ответа только по коду
GGO

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

2
Это создаст файл json, а не файл csv.
nvoigt
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.