将PostgreSQL的PL/pgSQL输出保存为CSV文件

Hof*_*off 853 sql csv postgresql postgresql-copy

将PL/pgSQL输出从PostgreSQL数据库保存到CSV文件的最简单方法是什么?

我正在使用PostgreSQL 8.4和pgAdmin III以及PSQL插件来运行查询.

IMS*_*SoP 1283

您想要在服务器上还是在客户端上生成文件?

服务器端

如果您想要易于重用或自动化的东西,可以使用Postgresql的内置COPY命令.例如

Copy (Select * From foo) To '/tmp/test.csv' With CSV DELIMITER ',';
Run Code Online (Sandbox Code Playgroud)

此方法完全在远程服务器上运行 - 它无法写入本地PC.它还需要作为Postgres"超级用户"(通常称为"root")运行,因为Postgres无法阻止它使用该机器的本地文件系统进行令人讨厌的事情.

这实际上并不意味着您必须以超级用户身份进行连接(自动化会产生不同类型的安全风险),因为您可以使用SECURITY DEFINER选项CREATE FUNCTION来创建一个像超级用户一样运行的功能.

关键部分是你的功能是执行额外的检查,而不仅仅是绕过安全 - 所以你可以写一个导出你需要的确切数据的函数,或者你可以写一些可以接受各种选项的东西,只要它们遇到严格的白名单.你需要检查两件事:

  1. 应该允许用户在磁盘上读/写哪些文件?例如,这可能是一个特定的目录,文件名可能必须具有合适的前缀或扩展名.
  2. 用户应该在数据库中读/写哪些?这通常由GRANT数据库中的s 定义,但该函数现在作为超级用户运行,因此通常"超出界限"的表将是完全可访问的.您可能不希望让某人调用您的函数并在"用户"表的末尾添加行...

我写了一篇扩展这种方法的博客文章,包括一些导出(或导入)符合严格条件的文件和表格的函数示例.


客户端

另一种方法是在客户端进行文件处理,即在您的应用程序或脚本中进行.Postgres服务器不需要知道你要复制到哪个文件,它只是吐出数据而客户端把它放在某个地方.

这个的基本语法是COPY TO STDOUT命令,像pgAdmin这样的图形工具会在一个很好的对话框中为你包装它.

psql命令行客户端有一个特殊的"元命令"之称\copy,这需要所有相同的选项,"真正的" COPY,但在运行客户端中:

\copy (Select * From foo) To '/tmp/test.csv' With CSV
Run Code Online (Sandbox Code Playgroud)

请注意,没有终止;,因为与SQL命令不同,元命令由换行符终止.

来自文档:

不要将COPY与psql指令\ copy混淆.\ copy调用COPY FROM STDIN或COPY TO STDOUT,然后将数据提取/存储在psql客户端可访问的文件中.因此,使用\ copy时,文件可访问性和访问权限取决于客户端而不是服务器.

您的应用程序编程语言可能也有推或获取数据的支持,但你不能一般使用COPY FROM STDIN/ TO STDOUT标准的SQL语句中,因为没有连接输入/输出流的方式.PHP的PostgreSQL处理程序(不是 PDO)包括非常基本的pg_copy_frompg_copy_to复制到PHP数组的函数,这些函数对于大型数据集可能效率不高.

  • 显然上面的例子有时需要用户成为超级用户,这里是普通人的版本;)回显"COPY(SELECT*from foo)to STDOUT with CSV HEADER"| psql -o'/tmp/test.csv'eatabase_name (121认同)
  • 它看起来像`\ copy`需要是一个单行.所以你没有得到你想要的格式化sql的美妙,只是在它周围放一个副本/函数. (12认同)
  • @Drachenfels:`\ copy`也可以 - 在那里,路径是相对于客户端的,并且不需要/允许使用分号.看我的编辑. (10认同)
  • @IMSoP:你如何将一个COPY语句添加到sql(在postgres 9.3上)函数?那么查询会保存到.csv文件中吗? (3认同)

sor*_*rin 490

有几种解决方案:

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
Run Code Online (Sandbox Code Playgroud)

所有这些都可以在脚本中使用,但我更喜欢#1.

4 pgadmin,但这不是可编写脚本的.

  • 恕我直言,第一个选项容易出错,因为它不包括导出数据中正确的逗号转义. (30认同)
  • 刚刚测试了逗号转义声明 - 这是真的,方法#1确实*不*在值中转义逗号. (21认同)
  • @Cerin -t是--tuples-only的同义词(关闭列名和结果行计数页脚的打印等) - 省略它以获取列标题 (7认同)
  • 此外,psql不引用单元格值,因此如果您的数据******使用分隔符,则您的文件将被破坏. (4认同)

Mar*_*luk 93

在终端(连接到db时)将输出设置为cvs文件

1)将字段分隔符设置为',':

\f ','
Run Code Online (Sandbox Code Playgroud)

2)设置输出格式不对齐:

\a
Run Code Online (Sandbox Code Playgroud)

3)仅显示元组:

\t
Run Code Online (Sandbox Code Playgroud)

4)设置输出:

\o '/tmp/yourOutputFile.csv'
Run Code Online (Sandbox Code Playgroud)

5)执行您的查询:

:select * from YOUR_TABLE
Run Code Online (Sandbox Code Playgroud)

6)输出:

\o
Run Code Online (Sandbox Code Playgroud)

然后,您就可以在此位置找到您的csv文件:

cd /tmp
Run Code Online (Sandbox Code Playgroud)

使用scp命令复制或使用nano编辑:

nano /tmp/yourOutputFile.csv
Run Code Online (Sandbox Code Playgroud)

  • 我通过注意"csv"输出将无法正确转义并且每次执行sql命令时结果都连接到输出文件,我会改进这个答案. (5认同)
  • 和\ o以便再次打印控制台 (4认同)
  • 这不会生成 CSV 文件,它只会将命令输出记录到文本文件(这不会使其以逗号分隔)。 (2认同)

ben*_*ams 36

如果您对特定表的所有列以及标题感兴趣,则可以使用

COPY table TO '/some_destdir/mycsv.csv' WITH CSV HEADER;
Run Code Online (Sandbox Code Playgroud)

这比一点点简单

COPY (SELECT * FROM table) TO '/some_destdir/mycsv.csv' WITH CSV HEADER;
Run Code Online (Sandbox Code Playgroud)

据我所知,这是等价的.


jos*_*rry 30

CSV导出统一

这些信息并没有得到很好的体现.由于这是我第二次需要得到这个,我会把它放在这里提醒自己,如果没有别的.

真的最好的方法(从postgres中获取CSV)就是使用COPY ... TO STDOUT命令.虽然你不想按照答案中的方式这样做.使用该命令的正确方法是:

COPY (select id, name from groups) TO STDOUT WITH CSV HEADER
Run Code Online (Sandbox Code Playgroud)

记住一个命令!

它非常适合在ssh上使用:

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

它非常适合在ssh中使用docker:

$ ssh pgserver.example.com 'docker exec -tu postgres postgres psql -d mydb -c "COPY groups TO STDOUT WITH CSV HEADER"' > groups.csv
Run Code Online (Sandbox Code Playgroud)

它在本地机器上甚至很棒:

$ psql -d mydb -c 'COPY groups TO STDOUT WITH CSV HEADER' > groups.csv
Run Code Online (Sandbox Code Playgroud)

或者在本地机器上的docker里面?:

docker exec -tu postgres postgres psql -d mydb -c 'COPY groups TO STDOUT WITH CSV HEADER' > groups.csv
Run Code Online (Sandbox Code Playgroud)

或者在kubernetes集群上,在docker中,通过HTTPS ??:

kubectl exec -t postgres-2592991581-ws2td 'psql -d mydb -c "COPY groups TO STDOUT WITH CSV HEADER"' > groups.csv
Run Code Online (Sandbox Code Playgroud)

多功能,多逗号!

你甚至?

是的我做了,这是我的笔记:

COPYses

使用/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,,
Run Code Online (Sandbox Code Playgroud)

其他工具

不,我只想在没有编译和/或安装工具的情况下从我的服务器中获取CSV.

  • 结果保存到哪里?我的查询已运行,​​但该文件没有显示在我的计算机上的任何位置。这就是我正在做的: COPY (select a,b from c where d = '1') TO STDOUT with CSVHEADER > abcd.csv (2认同)

mau*_*lus 23

我不得不使用\ COPY,因为我收到了错误消息:

ERROR:  could not open file "/filepath/places.csv" for writing: Permission denied
Run Code Online (Sandbox Code Playgroud)

所以我用过:

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

它正在发挥作用

  • 我也遇到了权限被拒绝的错误。通过首先发送到“/tmp”文件夹来修复它。例如:“\copy (SELECT * FROM messages) TO '/tmp/messages.csv' With CSV HEADER;” (2认同)

Dir*_*tel 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:~$
Run Code Online (Sandbox Code Playgroud)

有关man psql此处使用的选项,请参阅参考资料.

  • 这不是真正的CSV文件 - 如果数据中有逗号,请观看它 - 因此首选使用内置COPY支持.但是这种通用技术很方便,除了CSV之外,还可以用其他分隔格式从Postgres导出. (12认同)

小智 14

我正在使用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
Run Code Online (Sandbox Code Playgroud)


Luk*_*zda 12

新版本 - psql 12 - 将支持--csv.

psql - 开发

--csv

切换到CSV(逗号分隔值)输出模式.这相当于\ pset format 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
Run Code Online (Sandbox Code Playgroud)


Ama*_*ren 11

在pgAdmin III中,有一个从查询窗口导出到文件的选项.在主菜单中,它是Query - > Execute to file或者是一个执行相同操作的按钮(它是带有蓝色软盘的绿色三角形,而不是仅运行查询的普通绿色三角形).如果您没有从查询窗口运行查询,那么我将执行IMSoP建议并使用复制命令.


fph*_*ipe 9

我写了一个名为psql2csv封装COPY query TO STDOUT模式的小工具,产生了正确的CSV.它的界面类似于psql.

psql2csv [OPTIONS] < QUERY
psql2csv [OPTIONS] QUERY
Run Code Online (Sandbox Code Playgroud)

假定查询是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
Run Code Online (Sandbox Code Playgroud)

  • 效果很好。谢谢。 (2认同)
  • 太棒了,帮助我创建了自己的命令 (2认同)

Gui*_*goz 9

从 Postgres 12 开始,您可以更改输出格式:

\pset format csv
Run Code Online (Sandbox Code Playgroud)

允许使用以下格式:

aligned, asciidoc, csv, html, latex, latex-longtable, troff-ms, unaligned, wrapped
Run Code Online (Sandbox Code Playgroud)

如果您想导出请求的结果,可以使用该\o filename功能。

例子 :

\pset format csv

\o file.csv
SELECT * FROM table LIMIT 10;
\o

\pset format aligned
Run Code Online (Sandbox Code Playgroud)


pyA*_*ict 8

我尝试了几件事,但很少有人能够通过标题详细信息向我提供所需的CSV.

这对我有用.

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


And*_*ull 6

如果您有更长的查询并且您想使用psql,则将查询放入文件并使用以下命令:

psql -d my_db_name -t -A -F";" -f input-file.sql -o output-file.csv
Run Code Online (Sandbox Code Playgroud)

  • FWIW,我不得不使用 `-F","` 而不是 `-F";"` 来生成一个可以在 MS Excel 中正确打开的 CSV 文件 (3认同)

Mur*_*rli 5

要下载列名为 HEADER 的 CSV 文件,请使用以下命令:

Copy (Select * From tableName) To '/tmp/fileName.csv' With CSV HEADER;
Run Code Online (Sandbox Code Playgroud)