【问题标题】:Save PL/pgSQL output from PostgreSQL to a CSV file将 PL/pgSQL 输出从 PostgreSQL 保存到 CSV 文件
【发布时间】:2010-12-03 19:25:46
【问题描述】:

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

我正在使用带有 pgAdmin III 和 PSQL 插件的 PostgreSQL 8.4,我从中运行查询。

【问题讨论】:

标签: sql postgresql csv postgresql-copy


【解决方案1】:

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

【讨论】:

  • 这不是一个真正的 CSV 文件——如果数据中有逗号,请观察它的燃烧——因此首选使用内置的 COPY 支持。但是这种通用技术很方便,可以作为从 Postgres 以除 CSV 之外的其他分隔格式导出的快速技巧。
【解决方案2】:

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

服务器端

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

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

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

这实际上并不意味着您必须以超级用户身份连接(自动化这将是一种不同类型的安全风险),因为您可以使用the SECURITY DEFINER option to CREATE FUNCTION 来创建一个功能,就像您运行是超级用户

关键部分是您的函数可以执行额外的检查,而不仅仅是绕过安全性 - 因此您可以编写一个函数来导出您需要的确切数据,或者您可以编写一些可以接受各种选项的东西只要他们符合严格的白名单。您需要检查两件事:

  1. 应该允许用户在磁盘上读/写哪些文件?例如,这可能是一个特定的目录,并且文件名可能必须有一个合适的前缀或扩展名。
  2. 用户应该能够在数据库中读取/写入哪些?这通常由数据库中的GRANTs 定义,但该函数现在以超级用户身份运行,因此通常“越界”的表将可以完全访问。您可能不想让某人调用您的函数并在“用户”表的末尾添加行……

我写过a blog post expanding on this approach,包括一些导出(或导入)满足严格条件的文件和表的函数示例。


客户端

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

它的底层语法是COPY TO STDOUT 命令,pgAdmin 等图形工具会在一个漂亮的对话框中为您包装它。

psql 命令行客户端 有一个名为\copy 的特殊“元命令”,它采用与“真实”@ 相同的所有选项987654334@,但在客户端内部运行:

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

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

来自the docs

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

您的应用程序编程语言可能也支持推送或获取数据,但您通常不能在标准 SQL 语句中使用COPY FROM STDIN/TO STDOUT,因为无法连接输入/输出流。 PHP 的 PostgreSQL 处理程序 (not PDO) 包括非常基本的 pg_copy_frompg_copy_to 函数,它们可以复制到 PHP 数组或从 PHP 数组复制,这对于大型数据集可能效率不高。

【讨论】:

  • 显然上面的例子有时要求用户是超级用户,这里是普通人的版本;) echo "COPY (SELECT * from foo) TO STDOUT with CSV HEADER" | psql -o '/tmp/test.csv' 数据库名称
  • @Drachenfels: \copy 也有效——在那里,路径是相对于客户端的,不需要/不允许使用分号。查看我的编辑。
  • @IMSoP:如何将 COPY 语句添加到 sql(在 postgres 9.3 上)函数?所以查询被保存到 .csv 文件中?
  • 看来\copy 需要单行。因此,您无法按照自己想要的方式格式化 sql,而只是在其周围放置一个副本/函数。
  • @AndreSilva 正如答案所述,\copy 是一个特殊的元命令psql 命令行客户端。它不适用于其他客户端,例如 pgAdmin;他们可能会有自己的工具来完成这项工作,例如图形向导。
【解决方案3】:

在 pgAdmin III 中有一个选项可以从查询窗口导出到文件。在主菜单中它是 Query -> Execute to file 或者有一个按钮可以做同样的事情(它是一个带有蓝色软盘的绿色三角形,而不是只运行查询的纯绿色三角形)。如果您没有从查询窗口运行查询,那么我会执行 IMSoP 的建议并使用复制命令。

【讨论】:

  • IMSoP 的回答对我不起作用,因为我需要成为超级管理员。这是一种享受。谢谢!
【解决方案4】:

在终端(连接到数据库时)将输出设置为 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

【讨论】:

  • 和 \o 以便再次打印控制台
  • 这不会生成 CSV 文件,它只会将命令输出记录到文本文件中(不会以逗号分隔)。
  • @RuslanKabalin 是的,我刚刚注意到这一点并修改了创建逗号分隔输出 (cvs) 的指令
  • 我会改进这个答案,注意“csv”输出不会被正确转义,每次执行 sql 命令时,结果都会连接到输出文件。
  • 字段值中的换行符怎么样? COPY\copy 方法处理正确(转换为标准 CSV 格式);这是吗?
【解决方案5】:

有几种解决方案:

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 但这不是可编写脚本的。

【讨论】:

  • 恕我直言,第一个选项容易出错,因为它不包括在导出数据中正确转义逗号。
  • 另外,psql 不引用单元格值,因此如果您的 ANY 数据使用分隔符,您的文件将被损坏。
  • @Cerin -t 是 --tuples-only 的同义词(关闭列名和结果行计数页脚等的打印) - 省略它以获取列标题
  • 刚刚测试了逗号转义声明——确实如此,方法#1 在值中转义逗号。
  • 也使用“\pset 页脚”,这样文件中的行数就不会增加
【解决方案6】:

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

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

这比

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

据我所知,它们是等价的。

【讨论】:

  • 如果查询是自定义的(即具有列别名或连接不同的表),标题将打印出列别名,就像它在屏幕上显示一样。
【解决方案7】:

我正在使用不支持 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

【讨论】:

  • 太好了,谢谢!我使用 `psql -h dblocation -p port -U user -d dbname -F $',' --no-align -c "SELECT * FROM TABLE" > outfile.csv` 来获取 CSV。没有引用字段,但它足以满足我的目的
  • 仅供参考,您可以配置.pg_service.conf 将连接参数别名为psql service=default -F $'\t' ...
  • Redshift 支持UNLOAD
【解决方案8】:

JackDB,您的网络浏览器中的数据库客户端,让这变得非常简单。特别是如果你在 Heroku 上。

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

Source sup>
(来源:jackdb.com) sub>


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


注意:我与 JackDB 没有任何关系。我目前使用他们的免费服务,并认为这是一个很棒的产品。

【讨论】:

    【解决方案9】:

    我不得不使用 \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;
    

    它正在运行

    【讨论】:

    • 我也遇到了权限被拒绝错误。通过先发送到/tmp 文件夹来修复它。例如:\copy (SELECT * FROM messages) TO '/tmp/messages.csv' With CSV HEADER;
    【解决方案10】:

    如果您有更长的查询并且您喜欢使用 psql,那么将您的查询放到一个文件中并使用以下命令:

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

    【讨论】:

    • FWIW,我必须使用 -F"," 而不是 -F";" 来生成一个可以在 MS Excel 中正确打开的 CSV 文件
    【解决方案11】:

    我编写了一个名为 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
    

    【讨论】:

    • 效果很好。谢谢。
    【解决方案12】:
    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'
    

    【讨论】:

    • 请解释你做了什么编辑答案,避免只用代码回答
    • 感谢您提供此代码 sn-p,它可能会提供一些有限的短期帮助。一个正确的解释would greatly improve 其长期价值通过展示为什么这是解决问题的好方法,并将使其对未来有其他类似问题的读者更有用。请edit您的回答添加一些解释,包括您所做的假设。
    • 这将生成一个 json 文件,而不是 csv 文件。
    【解决方案13】:

    我尝试了几件事,但其中很少有人能够为我提供所需的带有标题详细信息的 CSV。

    这对我有用。

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

    【讨论】:

      【解决方案14】:

      CSV 导出统一

      这些信息并没有得到很好的体现。因为这是我第二次需要推导出这个,所以我会把它放在这里提醒自己,如果没有别的。

      真正做到这一点的最好方法(从 postgres 中获取 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 集群上,在 docker 中,通过 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 最终驻留的系统上执行,则这两个选项都需要后续文件移动。根据我的经验,当您主要使用远程服务器时,这是最有可能发生的情况。

      通过 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。

      【讨论】:

      • 结果保存到哪里?我的查询运行,但该文件没有显示在我的计算机上的任何位置。这就是我正在做的事情: COPY (select a,b from c where d = '1') TO STDOUT WITH CSVHEADER > abcd.csv
      • @kRazzyR 输出到 psql 命令的 stdout,所以最终无论你对 stdout 做什么都是数据去向的地方。在我的示例中,我使用 '> file.csv' 重定向到文件。您要确保它在通过 psql -c 参数发送到服务器的命令之外。请参阅“本地机器”示例。
      • 感谢您的完整解释。使用 psql 的复制命令非常复杂。我最终通常使用免费的数据库客户端(dbeaver 社区版)来导入和导出数据文件。它提供了很好的映射和格式化工具。您的回答提供了从远程系统复制的非常详细的示例。
      • 这是一个了不起的解决方案。非常感谢。
      【解决方案15】:

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

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

      【讨论】:

        【解决方案16】:

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

        psql - devel

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

        【讨论】:

          【解决方案17】:

          根据@skeller88 的要求,我将我的评论重新发布为答案,以免不阅读所有回复的人迷失它......

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

          DBeaver 社区版让连接数据库、发出查询以检索数据,然后下载结果集以将其保存为 CSV、JSON、SQL 或其他常见数据格式变得轻而易举。它是 TOAD for Postgres、TOAD for SQL Server 或 Toad for Oracle 的可行 FOSS 竞争对手。

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

          DBeaver 用户是否了解创建分析小部件以添加到 DBeaver 社区版的步骤?

          【讨论】:

            猜你喜欢
            • 2015-08-07
            • 1970-01-01
            • 1970-01-01
            • 2022-11-28
            • 2022-11-25
            • 2021-07-14
            • 2022-01-13
            • 1970-01-01
            相关资源
            最近更新 更多