Сохранить вывод 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.