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


Answers:


1366

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

服务器端

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

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

这种方法完全在远程服务器上运行 -无法写入本地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

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

文档

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

您的应用程序编程语言可能还支持推送或获取数据,但是由于无法连接输入/输出流,因此通常不能在标准SQL语句中使用COPY FROM STDIN/ TO STDOUT。PHP的PostgreSQL处理程序(不是 PDO)包括非常基本的功能pg_copy_from和可与pg_copy_toPHP数组进行复制的功能,这些功能对于大型数据集可能无效。


131
显然,上面的示例有时需要用户成为超级用户,这是普通用户的版本;psql -o'/tmp/test.csv'database_name
Drachenfels

10
@Drachenfels:也\copy可以工作-那里的路径是相对于客户端的,不需要/不允许使用分号。看到我的编辑。
krlmlr

3
@IMSoP:如何将COPY语句添加到sql(在postgres 9.3上)函数?那么查询是否保存到.csv文件?
乔。

12
看起来\copy需要成为一线客。因此,您不会获得按所需方式格式化sql的美,而只是围绕它放置一个副本/函数。
isaaclw 2014年

1
如答案所示,@ AndreSilva \copy命令行客户端中的psql特殊元命令。它无法在其他客户端(例如pgAdmin)中运行;他们可能会拥有自己的工具(例如图形向导)来完成这项工作。
IMSoP '18年

519

有几种解决方案:

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,但这不是脚本。


32
恕我直言,第一个选项是容易出错的,因为它不包括在导出的数据中正确转义逗号。
Piohen

4
另外,psql不会引用单元格值,因此,如果您的任何数据使用定界符,文件都将损坏。
塞林2014年

7
@Cerin -t是--tuples-only的同义词(关闭列名和结果行计数页脚的打印等)-省略它以获得列标题
ic3b3rg 2014年

21
刚刚测试逗号逃逸要求,这是真的,方法#1并没有价值观逃避逗号。
MrColes 2014年

1
还使用“ \ pset页脚”,因此文件中的行数不会增加
techbrownbags

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
和\ o以便再次打印控制台
metdos 2012年

2
这不会产生CSV文件,它只会将命令输出记录到文本文件中(不会将其用逗号分隔)。
Ruslan Kabalin 2012年

@RuslanKabalin是的,我刚刚注意到这一点,并修改了指令以创建逗号分隔的输出(cvs)
Marcin Wasiluk 2012年

5
我会通过指出“ csv”输出将无法正确转义来改善此答案,并且每次执行sql命令时,结果都将连接到输出文件。
丹尼·阿姆斯特朗

字段值中的换行符呢?的COPY\copy正确地接近手柄(转换为标准CSV格式); 做这个?
通配符

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具有列别名或连接不同的表),则标题将打印出列别名,就像在屏幕上显示的一样。
Devy

33

CSV导出统一

这些信息并没有很好地表示。由于这是我第二次需要导出此内容,因此将其放在此处以提醒自己是否没有其他内容。

真正做到这一点的最佳方法(从PostgreSQL中提取CSV)是使用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在docker内部使用:

$ 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内部?

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

还是在kubernetes集群中,通过HTTPS在docker中通过??:

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的系统上执行,则这两个选项都需要后续文件移动。以我的经验,这是最有可能的情况,当您主要使用远程服务器时。

通过ssh将TCP / IP隧道配置到远程系统以进行简单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
结果保存到哪里?我的查询正在运行,但是文件未显示在计算机上的任何位置。这就是我正在做的:从CSVHEADER到COPD(从c中选择a,b,其中d ='1')> abcd.csv
kRazzy R

1
@kRazzyR输出将输出到psql命令的stdout,因此最终您对stdout所做的任何操作都是将数据移到哪里。在我的示例中,我使用“> file.csv”重定向到文件。您要确保该命令不在通过psql -c参数发送到服务器的命令之外。请参阅“本地计算机”示例。
乔斯佩里

感谢您的完整解释。复制命令对psql来说是非常复杂的。我最终通常使用免费的数据库客户端(dbeaver社区版)来导入和导出数据文件。它提供了不错的映射和格式化工具。您的答案提供了从远程系统复制的详细示例。
Rich Lysakowski PhD

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支持。但是,这种通用技术非常适合作为一种快速技巧,可以从CSV以外的其他分隔格式从Postgres导出。
格雷格·史密斯,

16

我正在研究不支持该COPY TO功能的AWS Redshift 。

我的BI工具虽然支持制表符分隔的CSV,所以我使用了以下内容:

 psql -h dblocation -p port -U user -d dbname -F $'\t' --no-align -c "SELECT * FROM TABLE" > outfile.csv

16

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

psql-开发

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

11

在pgAdmin III中,有一个选项可以从查询窗口导出到文件。在主菜单中,它是“查询”->“执行到文件”,或者有一个按钮执行相同的操作(这是一个带有蓝色软盘的绿色三角形,而不是只运行查询的普通绿色三角形)。如果您不是从查询窗口运行查询,那么我将按照IMSoP的建议进行操作,并使用copy命令。


IMSoP的答案对我不起作用,因为我需要成为超级管理员。这工作了。谢谢!
Mike

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";"生成将在MS Excel中正确打开的CSV文件
CFL_Jeff,

4

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

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

1

我强烈建议使用JetBrains的数据库IDE DataGrip。您可以将SQL查询导出到CSV文件,并且可以轻松设置ssh隧道。当文档提到“结果集”时,它们表示控制台中SQL查询返回的结果。

我与DataGrip无关,我只是喜欢这个产品!


我猜这是因为缺少上下文/解释造成的,所以我已经链接到了DataGrip文档。如果有其他原因会降低投票率,请告诉我。我已经使用了上面的CLI解决方案,而对于较小的查询,DataGrip则要容易得多。
skeller88

DataGrip的问题在于它会夹住您的钱包。它不是免费的。在dbeaver.io上尝试DBeaver的社区版。它是面向SQL程序员,DBA和分析人员的FOSS多平台数据库工具,支持所有流行的数据库:MySQL,PostgreSQL,SQLite,Oracle,DB2,SQL Server,Sybase,MS Access,Teradata,Firebird,Hive,Presto等。
Rich Lysakowski PhD

酷,我会检查一下。您如何也将评论重新发布为答案呢?
skeller88 '19

0

JackDB是Web浏览器中的数据库客户端,它使此操作非常容易。特别是在Heroku上。

它使您可以连接到远程数据库并在它们上运行SQL查询。

                                                                                                                                                       来源 (来源:jackdb.comjackdb-heroku


连接数据库后,您可以运行查询并导出为CSV或TXT(请参阅右下角)。


jackdb导出

注意:我绝不隶属于JackDB。我目前使用他们的免费服务,并认为这是一个很棒的产品。


0

根据@ skeller88的请求,我将我的评论重新发布为答案,以免那些不读每个回复的人迷路。

DataGrip的问题在于它会夹住您的钱包。它不是免费的。在dbeaver.io上尝试DBeaver的社区版。它是面向SQL程序员,DBA和分析人员的FOSS多平台数据库工具,支持所有流行的数据库:MySQL,PostgreSQL,SQLite,Oracle,DB2,SQL Server,Sybase,MS Access,Teradata,Firebird,Hive,Presto等。

DBeaver Community Edition使得连接数据库,发出查询以检索数据,然后下载结果集以将其保存为CSV,JSON,SQL或其他常见数据格式变得很简单。它是TOAD for Postgres,TOAD for SQL Server或Toad for Oracle的可行的FOSS竞争对手。

我与DBeaver没有任何隶属关系。我喜欢价格和功能,但是我希望他们能更多地打开DBeaver / Eclipse应用程序,并使向DBeaver / Eclipse中添加分析小部件变得容易,而不是要求用户支付年度订阅费来直接在其中创建图表。应用程序。我的Java编码技能很生疏,我不想花数周的时间重新学习如何构建Eclipse小部件,却发现DBeaver禁用了向DBeaver Community Edition添加第三方小部件的功能。

DBeaver用户是否对创建要添加到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
感谢您提供此代码段,它可能会提供一些有限的短期帮助。通过说明为什么这是一个解决问题的好方法,适当的解释将大大提高其长期价值,对于其他存在类似问题的读者来说,这样做将更为有用。请编辑您的答案以添加一些解释,包括您所做的假设。
Toby Speight '18

2
这将产生一个json文件,而不是csv文件。
nvoigt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.